aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/glsl/linker.cpp553
-rw-r--r--mesalib/src/glsl/lower_vec_index_to_swizzle.cpp22
-rw-r--r--mesalib/src/mesa/drivers/common/meta.c113
-rw-r--r--mesalib/src/mesa/main/format_unpack.c120
-rw-r--r--mesalib/src/mesa/main/format_unpack.h8
-rw-r--r--mesalib/src/mesa/main/mtypes.h13
-rw-r--r--mesalib/src/mesa/swrast/s_readpix.c19
7 files changed, 773 insertions, 75 deletions
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 0306b7a1b..351680d43 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -1369,10 +1369,359 @@ demote_shader_inputs_and_outputs(gl_shader *sh, enum ir_variable_mode mode)
}
+/**
+ * Data structure tracking information about a transform feedback declaration
+ * during linking.
+ */
+class tfeedback_decl
+{
+public:
+ bool init(struct gl_shader_program *prog, const void *mem_ctx,
+ const char *input);
+ static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y);
+ bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog,
+ ir_variable *output_var);
+ bool store(struct gl_shader_program *prog,
+ struct gl_transform_feedback_info *info, unsigned buffer) const;
+
+
+ /**
+ * True if assign_location() has been called for this object.
+ */
+ bool is_assigned() const
+ {
+ return this->location != -1;
+ }
+
+ /**
+ * Determine whether this object refers to the variable var.
+ */
+ bool matches_var(ir_variable *var) const
+ {
+ return strcmp(var->name, this->var_name) == 0;
+ }
+
+ /**
+ * The total number of varying components taken up by this variable. Only
+ * valid if is_assigned() is true.
+ */
+ unsigned num_components() const
+ {
+ return this->vector_elements * this->matrix_columns;
+ }
+
+private:
+ /**
+ * The name that was supplied to glTransformFeedbackVaryings. Used for
+ * error reporting.
+ */
+ const char *orig_name;
+
+ /**
+ * The name of the variable, parsed from orig_name.
+ */
+ char *var_name;
+
+ /**
+ * True if the declaration in orig_name represents an array.
+ */
+ bool is_array;
+
+ /**
+ * If is_array is true, the array index that was specified in orig_name.
+ */
+ unsigned array_index;
+
+ /**
+ * The vertex shader output location that the linker assigned for this
+ * variable. -1 if a location hasn't been assigned yet.
+ */
+ int location;
+
+ /**
+ * If location != -1, the number of vector elements in this variable, or 1
+ * if this variable is a scalar.
+ */
+ unsigned vector_elements;
+
+ /**
+ * If location != -1, the number of matrix columns in this variable, or 1
+ * if this variable is not a matrix.
+ */
+ unsigned matrix_columns;
+};
+
+
+/**
+ * Initialize this object based on a string that was passed to
+ * glTransformFeedbackVaryings. If there is a parse error, the error is
+ * reported using linker_error(), and false is returned.
+ */
+bool
+tfeedback_decl::init(struct gl_shader_program *prog, const void *mem_ctx,
+ const char *input)
+{
+ /* We don't have to be pedantic about what is a valid GLSL variable name,
+ * because any variable with an invalid name can't exist in the IR anyway.
+ */
+
+ this->location = -1;
+ this->orig_name = input;
+
+ const char *bracket = strrchr(input, '[');
+
+ if (bracket) {
+ this->var_name = ralloc_strndup(mem_ctx, input, bracket - input);
+ if (sscanf(bracket, "[%u]", &this->array_index) == 1) {
+ this->is_array = true;
+ return true;
+ }
+ } else {
+ this->var_name = ralloc_strdup(mem_ctx, input);
+ this->is_array = false;
+ return true;
+ }
+
+ linker_error(prog, "Cannot parse transform feedback varying %s", input);
+ return false;
+}
+
+
+/**
+ * Determine whether two tfeedback_decl objects refer to the same variable and
+ * array index (if applicable).
+ */
+bool
+tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
+{
+ if (strcmp(x.var_name, y.var_name) != 0)
+ return false;
+ if (x.is_array != y.is_array)
+ return false;
+ if (x.is_array && x.array_index != y.array_index)
+ return false;
+ return true;
+}
+
+
+/**
+ * Assign a location for this tfeedback_decl object based on the location
+ * assignment in output_var.
+ *
+ * If an error occurs, the error is reported through linker_error() and false
+ * is returned.
+ */
+bool
+tfeedback_decl::assign_location(struct gl_context *ctx,
+ struct gl_shader_program *prog,
+ ir_variable *output_var)
+{
+ if (output_var->type->is_array()) {
+ /* Array variable */
+ if (!this->is_array) {
+ linker_error(prog, "Transform feedback varying %s found, "
+ "but it's not an array ([] not expected).",
+ this->orig_name);
+ return false;
+ }
+ /* Check array bounds. */
+ if (this->array_index >=
+ (unsigned) output_var->type->array_size()) {
+ linker_error(prog, "Transform feedback varying %s has index "
+ "%i, but the array size is %i.",
+ this->orig_name, this->array_index,
+ output_var->type->array_size());
+ return false;
+ }
+ const unsigned matrix_cols =
+ output_var->type->fields.array->matrix_columns;
+ this->location = output_var->location + this->array_index * matrix_cols;
+ this->vector_elements = output_var->type->fields.array->vector_elements;
+ this->matrix_columns = matrix_cols;
+ } else {
+ /* Regular variable (scalar, vector, or matrix) */
+ if (this->is_array) {
+ linker_error(prog, "Transform feedback varying %s found, "
+ "but it's an array ([] expected).",
+ this->orig_name);
+ return false;
+ }
+ this->location = output_var->location;
+ this->vector_elements = output_var->type->vector_elements;
+ this->matrix_columns = output_var->type->matrix_columns;
+ }
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * the total number of components to capture in any varying
+ * variable in <varyings> is greater than the constant
+ * MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT and the
+ * buffer mode is SEPARATE_ATTRIBS_EXT;
+ */
+ if (prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS &&
+ this->num_components() >
+ ctx->Const.MaxTransformFeedbackSeparateComponents) {
+ linker_error(prog, "Transform feedback varying %s exceeds "
+ "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS.",
+ this->orig_name);
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Update gl_transform_feedback_info to reflect this tfeedback_decl.
+ *
+ * If an error occurs, the error is reported through linker_error() and false
+ * is returned.
+ */
+bool
+tfeedback_decl::store(struct gl_shader_program *prog,
+ struct gl_transform_feedback_info *info,
+ unsigned buffer) const
+{
+ if (!this->is_assigned()) {
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * any variable name specified in the <varyings> array is not
+ * declared as an output in the geometry shader (if present) or
+ * the vertex shader (if no geometry shader is present);
+ */
+ linker_error(prog, "Transform feedback varying %s undeclared.",
+ this->orig_name);
+ return false;
+ }
+ for (unsigned v = 0; v < this->matrix_columns; ++v) {
+ info->Outputs[info->NumOutputs].OutputRegister = this->location + v;
+ info->Outputs[info->NumOutputs].NumComponents = this->vector_elements;
+ info->Outputs[info->NumOutputs].OutputBuffer = buffer;
+ ++info->NumOutputs;
+ }
+ return true;
+}
+
+
+/**
+ * Parse all the transform feedback declarations that were passed to
+ * glTransformFeedbackVaryings() and store them in tfeedback_decl objects.
+ *
+ * If an error occurs, the error is reported through linker_error() and false
+ * is returned.
+ */
+static bool
+parse_tfeedback_decls(struct gl_shader_program *prog, const void *mem_ctx,
+ unsigned num_names, char **varying_names,
+ tfeedback_decl *decls)
+{
+ for (unsigned i = 0; i < num_names; ++i) {
+ if (!decls[i].init(prog, mem_ctx, varying_names[i]))
+ return false;
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * any two entries in the <varyings> array specify the same varying
+ * variable;
+ *
+ * We interpret this to mean "any two entries in the <varyings> array
+ * specify the same varying variable and array index", since transform
+ * feedback of arrays would be useless otherwise.
+ */
+ for (unsigned j = 0; j < i; ++j) {
+ if (tfeedback_decl::is_same(decls[i], decls[j])) {
+ linker_error(prog, "Transform feedback varying %s specified "
+ "more than once.", varying_names[i]);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+/**
+ * Assign a location for a variable that is produced in one pipeline stage
+ * (the "producer") and consumed in the next stage (the "consumer").
+ *
+ * \param input_var is the input variable declaration in the consumer.
+ *
+ * \param output_var is the output variable declaration in the producer.
+ *
+ * \param input_index is the counter that keeps track of assigned input
+ * locations in the consumer.
+ *
+ * \param output_index is the counter that keeps track of assigned output
+ * locations in the producer.
+ *
+ * It is permissible for \c input_var to be NULL (this happens if a variable
+ * is output by the producer and consumed by transform feedback, but not
+ * consumed by the consumer).
+ *
+ * If the variable has already been assigned a location, this function has no
+ * effect.
+ */
+void
+assign_varying_location(ir_variable *input_var, ir_variable *output_var,
+ unsigned *input_index, unsigned *output_index)
+{
+ if (output_var->location != -1) {
+ /* Location already assigned. */
+ return;
+ }
+
+ if (input_var) {
+ assert(input_var->location == -1);
+ input_var->location = *input_index;
+ }
+
+ output_var->location = *output_index;
+
+ /* FINISHME: Support for "varying" records in GLSL 1.50. */
+ assert(!output_var->type->is_record());
+
+ if (output_var->type->is_array()) {
+ const unsigned slots = output_var->type->length
+ * output_var->type->fields.array->matrix_columns;
+
+ *output_index += slots;
+ *input_index += slots;
+ } else {
+ const unsigned slots = output_var->type->matrix_columns;
+
+ *output_index += slots;
+ *input_index += slots;
+ }
+}
+
+
+/**
+ * Assign locations for all variables that are produced in one pipeline stage
+ * (the "producer") and consumed in the next stage (the "consumer").
+ *
+ * Variables produced by the producer may also be consumed by transform
+ * feedback.
+ *
+ * \param num_tfeedback_decls is the number of declarations indicating
+ * variables that may be consumed by transform feedback.
+ *
+ * \param tfeedback_decls is a pointer to an array of tfeedback_decl objects
+ * representing the result of parsing the strings passed to
+ * glTransformFeedbackVaryings(). assign_location() will be called for
+ * each of these objects that matches one of the outputs of the
+ * producer.
+ *
+ * When num_tfeedback_decls is nonzero, it is permissible for the consumer to
+ * be NULL. In this case, varying locations are assigned solely based on the
+ * requirements of transform feedback.
+ */
bool
assign_varying_locations(struct gl_context *ctx,
struct gl_shader_program *prog,
- gl_shader *producer, gl_shader *consumer)
+ gl_shader *producer, gl_shader *consumer,
+ unsigned num_tfeedback_decls,
+ tfeedback_decl *tfeedback_decls)
{
/* FINISHME: Set dynamically when geometry shader support is added. */
unsigned output_index = VERT_RESULT_VAR0;
@@ -1390,79 +1739,77 @@ assign_varying_locations(struct gl_context *ctx,
*/
link_invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0);
- link_invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
+ if (consumer)
+ link_invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
foreach_list(node, producer->ir) {
ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
- if ((output_var == NULL) || (output_var->mode != ir_var_out)
- || (output_var->location != -1))
+ if ((output_var == NULL) || (output_var->mode != ir_var_out))
continue;
- ir_variable *const input_var =
- consumer->symbols->get_variable(output_var->name);
-
- if ((input_var == NULL) || (input_var->mode != ir_var_in))
- continue;
-
- assert(input_var->location == -1);
-
- output_var->location = output_index;
- input_var->location = input_index;
-
- /* FINISHME: Support for "varying" records in GLSL 1.50. */
- assert(!output_var->type->is_record());
+ ir_variable *input_var =
+ consumer ? consumer->symbols->get_variable(output_var->name) : NULL;
- if (output_var->type->is_array()) {
- const unsigned slots = output_var->type->length
- * output_var->type->fields.array->matrix_columns;
+ if (input_var && input_var->mode != ir_var_in)
+ input_var = NULL;
- output_index += slots;
- input_index += slots;
- } else {
- const unsigned slots = output_var->type->matrix_columns;
+ if (input_var) {
+ assign_varying_location(input_var, output_var, &input_index,
+ &output_index);
+ }
- output_index += slots;
- input_index += slots;
+ for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+ if (!tfeedback_decls[i].is_assigned() &&
+ tfeedback_decls[i].matches_var(output_var)) {
+ if (output_var->location == -1) {
+ assign_varying_location(input_var, output_var, &input_index,
+ &output_index);
+ }
+ if (!tfeedback_decls[i].assign_location(ctx, prog, output_var))
+ return false;
+ }
}
}
unsigned varying_vectors = 0;
- foreach_list(node, consumer->ir) {
- ir_variable *const var = ((ir_instruction *) node)->as_variable();
-
- if ((var == NULL) || (var->mode != ir_var_in))
- continue;
-
- if (var->location == -1) {
- if (prog->Version <= 120) {
- /* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec:
- *
- * Only those varying variables used (i.e. read) in
- * the fragment shader executable must be written to
- * by the vertex shader executable; declaring
- * superfluous varying variables in a vertex shader is
- * permissible.
- *
- * We interpret this text as meaning that the VS must
- * write the variable for the FS to read it. See
- * "glsl1-varying read but not written" in piglit.
- */
-
- linker_error(prog, "fragment shader varying %s not written "
- "by vertex shader\n.", var->name);
- }
+ if (consumer) {
+ foreach_list(node, consumer->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->mode != ir_var_in))
+ continue;
+
+ if (var->location == -1) {
+ if (prog->Version <= 120) {
+ /* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec:
+ *
+ * Only those varying variables used (i.e. read) in
+ * the fragment shader executable must be written to
+ * by the vertex shader executable; declaring
+ * superfluous varying variables in a vertex shader is
+ * permissible.
+ *
+ * We interpret this text as meaning that the VS must
+ * write the variable for the FS to read it. See
+ * "glsl1-varying read but not written" in piglit.
+ */
+
+ linker_error(prog, "fragment shader varying %s not written "
+ "by vertex shader\n.", var->name);
+ }
- /* An 'in' variable is only really a shader input if its
- * value is written by the previous stage.
- */
- var->mode = ir_var_auto;
- } else {
- /* The packing rules are used for vertex shader inputs are also used
- * for fragment shader inputs.
- */
- varying_vectors += count_attribute_slots(var->type);
+ /* An 'in' variable is only really a shader input if its
+ * value is written by the previous stage.
+ */
+ var->mode = ir_var_auto;
+ } else {
+ /* The packing rules are used for vertex shader inputs are also
+ * used for fragment shader inputs.
+ */
+ varying_vectors += count_attribute_slots(var->type);
+ }
}
}
@@ -1487,9 +1834,54 @@ assign_varying_locations(struct gl_context *ctx,
}
+/**
+ * Store transform feedback location assignments into
+ * prog->LinkedTransformFeedback based on the data stored in tfeedback_decls.
+ *
+ * If an error occurs, the error is reported through linker_error() and false
+ * is returned.
+ */
+static bool
+store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
+ unsigned num_tfeedback_decls,
+ tfeedback_decl *tfeedback_decls)
+{
+ unsigned total_tfeedback_components = 0;
+ prog->LinkedTransformFeedback.NumOutputs = 0;
+ for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+ unsigned buffer =
+ prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS ? i : 0;
+ if (!tfeedback_decls[i].store(prog, &prog->LinkedTransformFeedback,
+ buffer))
+ return false;
+ total_tfeedback_components += tfeedback_decls[i].num_components();
+ }
+
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * the total number of components to capture is greater than
+ * the constant MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT
+ * and the buffer mode is INTERLEAVED_ATTRIBS_EXT.
+ */
+ if (prog->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS &&
+ total_tfeedback_components >
+ ctx->Const.MaxTransformFeedbackInterleavedComponents) {
+ linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
+ "limit has been exceeded.");
+ return false;
+ }
+
+ return true;
+}
+
+
void
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
{
+ tfeedback_decl *tfeedback_decls = NULL;
+ unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying;
+
void *mem_ctx = ralloc_context(NULL); // temporary linker context
prog->LinkStatus = false;
@@ -1656,19 +2048,54 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
break;
}
+ if (num_tfeedback_decls != 0) {
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * the <count> specified by TransformFeedbackVaryingsEXT is
+ * non-zero, but the program object has no vertex or geometry
+ * shader;
+ */
+ if (prev >= MESA_SHADER_FRAGMENT) {
+ linker_error(prog, "Transform feedback varyings specified, but "
+ "no vertex or geometry shader is present.");
+ goto done;
+ }
+
+ tfeedback_decls = ralloc_array(mem_ctx, tfeedback_decl,
+ prog->TransformFeedback.NumVarying);
+ if (!parse_tfeedback_decls(prog, mem_ctx, num_tfeedback_decls,
+ prog->TransformFeedback.VaryingNames,
+ tfeedback_decls))
+ goto done;
+ }
+
for (unsigned i = prev + 1; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] == NULL)
continue;
- if (!assign_varying_locations(ctx, prog,
- prog->_LinkedShaders[prev],
- prog->_LinkedShaders[i])) {
+ if (!assign_varying_locations(
+ ctx, prog, prog->_LinkedShaders[prev], prog->_LinkedShaders[i],
+ i == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
+ tfeedback_decls))
goto done;
- }
prev = i;
}
+ if (prev != MESA_SHADER_FRAGMENT && num_tfeedback_decls != 0) {
+ /* There was no fragment shader, but we still have to assign varying
+ * locations for use by transform feedback.
+ */
+ if (!assign_varying_locations(
+ ctx, prog, prog->_LinkedShaders[prev], NULL, num_tfeedback_decls,
+ tfeedback_decls))
+ goto done;
+ }
+
+ if (!store_tfeedback_info(ctx, prog, num_tfeedback_decls, tfeedback_decls))
+ goto done;
+
if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
demote_shader_inputs_and_outputs(prog->_LinkedShaders[MESA_SHADER_VERTEX],
ir_var_out);
diff --git a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
index c7630c28a..46fd6ace1 100644
--- a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
+++ b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
@@ -33,6 +33,7 @@
#include "ir_visitor.h"
#include "ir_optimization.h"
#include "glsl_types.h"
+#include "main/macros.h"
/**
* Visitor class for replacing expressions with ir_constant values.
@@ -76,8 +77,25 @@ ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
void *ctx = ralloc_parent(ir);
this->progress = true;
- return new(ctx) ir_swizzle(deref->array,
- ir_constant->value.i[0], 0, 0, 0, 1);
+
+ /* Page 40 of the GLSL 1.20 spec says:
+ *
+ * "When indexing with non-constant expressions, behavior is undefined
+ * if the index is negative, or greater than or equal to the size of
+ * the vector."
+ *
+ * The quoted spec text mentions non-constant expressions, but this code
+ * operates on constants. These constants are the result of non-constant
+ * expressions that have been optimized to constants. The common case here
+ * is a loop counter from an unrolled loop that is used to index a vector.
+ *
+ * The ir_swizzle constructor gets angry if the index is negative or too
+ * large. For simplicity sake, just clamp the index to [0, size-1].
+ */
+ const int i = MIN2(MAX2(ir_constant->value.i[0], 0),
+ (deref->array->type->vector_elements - 1));
+
+ return new(ctx) ir_swizzle(deref->array, i, 0, 0, 0, 1);
}
ir_visitor_status
diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c
index 3e553341d..8d589e4c3 100644
--- a/mesalib/src/mesa/drivers/common/meta.c
+++ b/mesalib/src/mesa/drivers/common/meta.c
@@ -182,7 +182,6 @@ struct save_state
GLboolean Lighting;
};
-
/**
* Temporary texture used for glBlitFramebuffer, glDrawPixels, etc.
* This is currently shared by all the meta ops. But we could create a
@@ -221,6 +220,9 @@ struct clear_state
GLuint VBO;
GLuint ShaderProg;
GLint ColorLocation;
+
+ GLuint IntegerShaderProg;
+ GLint IntegerColorLocation;
};
@@ -310,6 +312,67 @@ struct gl_meta_state
struct drawtex_state DrawTex; /**< For _mesa_meta_DrawTex() */
};
+static GLuint
+compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB *source)
+{
+ GLuint shader;
+ GLint ok, size;
+ GLchar *info;
+
+ shader = _mesa_CreateShaderObjectARB(target);
+ _mesa_ShaderSourceARB(shader, 1, &source, NULL);
+ _mesa_CompileShaderARB(shader);
+
+ _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &ok);
+ if (ok)
+ return shader;
+
+ _mesa_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
+ if (size == 0)
+ return 0;
+
+ info = malloc(size);
+ if (!info)
+ return 0;
+
+ _mesa_GetProgramInfoLog(shader, size, NULL, info);
+ _mesa_problem(ctx,
+ "meta program compile failed:\n%s\n"
+ "source:\n%s\n",
+ info, source);
+
+ free(info);
+
+ return 0;
+}
+
+static GLuint
+link_program_with_debug(struct gl_context *ctx, GLuint program)
+{
+ GLint ok, size;
+ GLchar *info;
+
+ _mesa_LinkProgramARB(program);
+
+ _mesa_GetProgramiv(program, GL_LINK_STATUS, &ok);
+ if (ok)
+ return program;
+
+ _mesa_GetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
+ if (size == 0)
+ return 0;
+
+ info = malloc(size);
+ if (!info)
+ return 0;
+
+ _mesa_GetProgramInfoLog(program, size, NULL, info);
+ _mesa_problem(ctx, "meta program link failed:\n%s", info);
+
+ free(info);
+
+ return 0;
+}
/**
* Initialize meta-ops for a context.
@@ -1646,6 +1709,22 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
"{\n"
" gl_FragColor = color;\n"
"}\n";
+ const char *vs_int_source =
+ "#version 130\n"
+ "attribute vec4 position;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = position;\n"
+ "}\n";
+ const char *fs_int_source =
+ "#version 130\n"
+ "uniform ivec4 color;\n"
+ "out ivec4 out_color;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " out_color = color;\n"
+ "}\n";
GLuint vs, fs;
if (clear->ArrayObj != 0)
@@ -1679,6 +1758,26 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
clear->ColorLocation = _mesa_GetUniformLocationARB(clear->ShaderProg,
"color");
+
+ if (ctx->Const.GLSLVersion >= 130) {
+ vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source);
+ fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source);
+
+ clear->IntegerShaderProg = _mesa_CreateProgramObjectARB();
+ _mesa_AttachShader(clear->IntegerShaderProg, fs);
+ _mesa_AttachShader(clear->IntegerShaderProg, vs);
+ _mesa_BindAttribLocationARB(clear->IntegerShaderProg, 0, "position");
+
+ /* Note that user-defined out attributes get automatically assigned
+ * locations starting from 0, so we don't need to explicitly
+ * BindFragDataLocation to 0.
+ */
+
+ link_program_with_debug(ctx, clear->IntegerShaderProg);
+
+ clear->IntegerColorLocation =
+ _mesa_GetUniformLocationARB(clear->IntegerShaderProg, "color");
+ }
}
/**
@@ -1722,9 +1821,15 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
meta_glsl_clear_init(ctx, clear);
- _mesa_UseProgramObjectARB(clear->ShaderProg);
- _mesa_Uniform4fvARB(clear->ColorLocation, 1,
- ctx->Color.ClearColor.f);
+ if (fb->_IntegerColor) {
+ _mesa_UseProgramObjectARB(clear->IntegerShaderProg);
+ _mesa_Uniform4ivARB(clear->IntegerColorLocation, 1,
+ ctx->Color.ClearColor.i);
+ } else {
+ _mesa_UseProgramObjectARB(clear->ShaderProg);
+ _mesa_Uniform4fvARB(clear->ColorLocation, 1,
+ ctx->Color.ClearColor.f);
+ }
_mesa_BindVertexArray(clear->ArrayObj);
_mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO);
diff --git a/mesalib/src/mesa/main/format_unpack.c b/mesalib/src/mesa/main/format_unpack.c
index eaa33dfdb..525bbcb1c 100644
--- a/mesalib/src/mesa/main/format_unpack.c
+++ b/mesalib/src/mesa/main/format_unpack.c
@@ -1258,7 +1258,127 @@ _mesa_unpack_rgba_row(gl_format format, GLuint n,
}
}
+static void
+unpack_int_rgba_RGBA_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ memcpy(dst, src, n * 4 * sizeof(GLuint));
+}
+
+static void
+unpack_int_rgba_RGB_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = src[i * 3 + 0];
+ dst[i][1] = src[i * 3 + 1];
+ dst[i][2] = src[i * 3 + 2];
+ dst[i][3] = 1;
+ }
+}
+
+static void
+unpack_int_rgba_RG_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = src[i * 2 + 0];
+ dst[i][1] = src[i * 2 + 1];
+ dst[i][2] = 0;
+ dst[i][3] = 1;
+ }
+}
+
+static void
+unpack_int_rgba_R_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = src[i];
+ dst[i][1] = 0;
+ dst[i][2] = 0;
+ dst[i][3] = 1;
+ }
+}
+
+static void
+unpack_int_rgba_LUMINANCE_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = dst[i][1] = dst[i][2] = src[i];
+ dst[i][3] = 1;
+ }
+}
+static void
+unpack_int_rgba_LUMINANCE_ALPHA_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = dst[i][1] = dst[i][2] = src[i * 2 + 0];
+ dst[i][3] = src[i * 2 + 1];
+ }
+}
+
+static void
+unpack_int_rgba_INTENSITY_UINT32(const GLuint *src, GLuint dst[][4], GLuint n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++) {
+ dst[i][0] = dst[i][1] = dst[i][2] = dst[i][3] = src[i];
+ }
+}
+
+void
+_mesa_unpack_int_rgba_row(gl_format format, GLuint n,
+ const void *src, GLuint dst[][4])
+{
+ switch (format) {
+ /* Since there won't be any sign extension happening, there's no need to
+ * make separate paths for 32-bit-to-32-bit integer unpack.
+ */
+ case MESA_FORMAT_RGBA_UINT32:
+ case MESA_FORMAT_RGBA_INT32:
+ unpack_int_rgba_RGBA_UINT32(src, dst, n);
+ break;
+ case MESA_FORMAT_RGB_UINT32:
+ case MESA_FORMAT_RGB_INT32:
+ unpack_int_rgba_RGB_UINT32(src, dst, n);
+ break;
+ case MESA_FORMAT_RG_UINT32:
+ case MESA_FORMAT_RG_INT32:
+ unpack_int_rgba_RG_UINT32(src, dst, n);
+ break;
+ case MESA_FORMAT_R_UINT32:
+ case MESA_FORMAT_R_INT32:
+ unpack_int_rgba_R_UINT32(src, dst, n);
+ break;
+
+ case MESA_FORMAT_LUMINANCE_UINT32:
+ case MESA_FORMAT_LUMINANCE_INT32:
+ unpack_int_rgba_LUMINANCE_UINT32(src, dst, n);
+ break;
+ case MESA_FORMAT_LUMINANCE_ALPHA_UINT32:
+ case MESA_FORMAT_LUMINANCE_ALPHA_INT32:
+ unpack_int_rgba_LUMINANCE_ALPHA_UINT32(src, dst, n);
+ break;
+ case MESA_FORMAT_INTENSITY_UINT32:
+ case MESA_FORMAT_INTENSITY_INT32:
+ unpack_int_rgba_INTENSITY_UINT32(src, dst, n);
+ break;
+
+ default:
+ _mesa_problem(NULL, "%s: bad format %s", __FUNCTION__,
+ _mesa_get_format_name(format));
+ return;
+ }
+}
/**
* Unpack a 2D rect of pixels returning float RGBA colors.
diff --git a/mesalib/src/mesa/main/format_unpack.h b/mesalib/src/mesa/main/format_unpack.h
index a8a829c88..0d13a2d39 100644
--- a/mesalib/src/mesa/main/format_unpack.h
+++ b/mesalib/src/mesa/main/format_unpack.h
@@ -29,12 +29,20 @@ _mesa_unpack_rgba_row(gl_format format, GLuint n,
const void *src, GLfloat dst[][4]);
+void
+_mesa_unpack_int_rgba_row(gl_format format, GLuint n,
+ const void *src, GLuint dst[][4]);
+
extern void
_mesa_unpack_rgba_block(gl_format format,
const void *src, GLint srcRowStride,
GLfloat dst[][4], GLint dstRowStride,
GLuint x, GLuint y, GLuint width, GLuint height);
+extern void
+_mesa_unpack_uint_rgba_row(gl_format format, GLuint n,
+ const void *src, GLuint dst[][4]);
+
extern void
_mesa_unpack_float_z_row(gl_format format, GLuint n,
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 58dc9af0f..adcbaeb19 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1824,6 +1824,16 @@ struct prog_instruction;
struct gl_program_parameter_list;
struct gl_uniform_list;
+/** Post-link transform feedback info. */
+struct gl_transform_feedback_info {
+ unsigned NumOutputs;
+
+ struct {
+ unsigned OutputRegister;
+ unsigned OutputBuffer;
+ unsigned NumComponents;
+ } Outputs[MAX_PROGRAM_OUTPUTS];
+};
/**
* Base class for any kind of program object
@@ -2206,6 +2216,9 @@ struct gl_shader_program
GLchar **VaryingNames; /**< Array [NumVarying] of char * */
} TransformFeedback;
+ /** Post-link transform feedback info. */
+ struct gl_transform_feedback_info LinkedTransformFeedback;
+
/** Geometry shader state - copied into gl_geometry_program at link time */
struct {
GLint VerticesOut;
diff --git a/mesalib/src/mesa/swrast/s_readpix.c b/mesalib/src/mesa/swrast/s_readpix.c
index 4438b9a20..b5618e884 100644
--- a/mesalib/src/mesa/swrast/s_readpix.c
+++ b/mesalib/src/mesa/swrast/s_readpix.c
@@ -236,7 +236,10 @@ slow_read_rgba_pixels( struct gl_context *ctx,
GLbitfield transferOps )
{
struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
- GLfloat rgba[MAX_WIDTH][4];
+ union {
+ float f[MAX_WIDTH][4];
+ unsigned int i[MAX_WIDTH][4];
+ } rgba;
GLubyte *dst, *map;
int dstStride, stride, j;
@@ -248,11 +251,15 @@ slow_read_rgba_pixels( struct gl_context *ctx,
&map, &stride);
for (j = 0; j < height; j++) {
- _mesa_unpack_rgba_row(_mesa_get_srgb_format_linear(rb->Format),
- width, map, rgba);
- _mesa_pack_rgba_span_float(ctx, width, rgba, format, type, dst,
- packing, transferOps);
-
+ if (_mesa_is_integer_format(format)) {
+ _mesa_unpack_int_rgba_row(rb->Format, width, map, rgba.i);
+ _mesa_pack_rgba_span_int(ctx, width, rgba.i, format, type, dst);
+ } else {
+ _mesa_unpack_rgba_row(_mesa_get_srgb_format_linear(rb->Format),
+ width, map, rgba.f);
+ _mesa_pack_rgba_span_float(ctx, width, rgba.f, format, type, dst,
+ packing, transferOps);
+ }
dst += dstStride;
map += stride;
}