diff options
Diffstat (limited to 'mesalib/src')
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 553 | ||||
-rw-r--r-- | mesalib/src/glsl/lower_vec_index_to_swizzle.cpp | 22 | ||||
-rw-r--r-- | mesalib/src/mesa/drivers/common/meta.c | 113 | ||||
-rw-r--r-- | mesalib/src/mesa/main/format_unpack.c | 120 | ||||
-rw-r--r-- | mesalib/src/mesa/main/format_unpack.h | 8 | ||||
-rw-r--r-- | mesalib/src/mesa/main/mtypes.h | 13 | ||||
-rw-r--r-- | mesalib/src/mesa/swrast/s_readpix.c | 19 |
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; } |