diff options
Diffstat (limited to 'mesalib/src/glsl/linker.cpp')
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 143 |
1 files changed, 92 insertions, 51 deletions
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index e8472d446..0d85aeee6 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -246,7 +246,8 @@ count_attribute_slots(const glsl_type *t) /** * Verify that a vertex shader executable meets all semantic requirements. * - * Also sets prog->Vert.UsesClipDistance as a side effect. + * Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize + * as a side effect. * * \param shader Vertex shader executable to be verified */ @@ -264,6 +265,8 @@ validate_vertex_shader_executable(struct gl_shader_program *prog, return false; } + prog->Vert.ClipDistanceArraySize = 0; + if (prog->Version >= 130) { /* From section 7.1 (Vertex Shader Special Variables) of the * GLSL 1.30 spec: @@ -282,6 +285,10 @@ validate_vertex_shader_executable(struct gl_shader_program *prog, return false; } prog->Vert.UsesClipDistance = clip_distance.variable_found(); + ir_variable *clip_distance_var = + shader->symbols->get_variable("gl_ClipDistance"); + if (clip_distance_var) + prog->Vert.ClipDistanceArraySize = clip_distance_var->type->length; } return true; @@ -1381,7 +1388,7 @@ public: 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, + bool store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, unsigned varying) const; @@ -1399,7 +1406,10 @@ public: */ bool matches_var(ir_variable *var) const { - return strcmp(var->name, this->var_name) == 0; + if (this->is_clip_distance_mesa) + return strcmp(var->name, "gl_ClipDistanceMESA") == 0; + else + return strcmp(var->name, this->var_name) == 0; } /** @@ -1408,7 +1418,10 @@ public: */ unsigned num_components() const { - return this->vector_elements * this->matrix_columns; + if (this->is_clip_distance_mesa) + return this->size; + else + return this->vector_elements * this->matrix_columns * this->size; } private: @@ -1434,11 +1447,10 @@ private: unsigned array_subscript; /** - * Which component to extract from the vertex shader output location that - * the linker assigned to this variable. -1 if all components should be - * extracted. + * True if the variable is gl_ClipDistance and the driver lowers + * gl_ClipDistance to gl_ClipDistanceMESA. */ - int single_component; + bool is_clip_distance_mesa; /** * The vertex shader output location that the linker assigned for this @@ -1484,7 +1496,7 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog, this->location = -1; this->orig_name = input; - this->single_component = -1; + this->is_clip_distance_mesa = false; const char *bracket = strrchr(input, '['); @@ -1500,17 +1512,13 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog, this->is_subscripted = false; } - /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, we need - * to convert a request for gl_ClipDistance[n] into a request for a - * component of gl_ClipDistanceMESA[n/4]. + /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, this + * class must behave specially to account for the fact that gl_ClipDistance + * is converted from a float[8] to a vec4[2]. */ if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance && strcmp(this->var_name, "gl_ClipDistance") == 0) { - this->var_name = "gl_ClipDistanceMESA"; - if (this->is_subscripted) { - this->single_component = this->array_subscript % 4; - this->array_subscript /= 4; - } + this->is_clip_distance_mesa = true; } return true; @@ -1530,8 +1538,6 @@ tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y) return false; if (x.is_subscripted && x.array_subscript != y.array_subscript) return false; - if (x.single_component != y.single_component) - return false; return true; } @@ -1552,27 +1558,36 @@ tfeedback_decl::assign_location(struct gl_context *ctx, /* Array variable */ const unsigned matrix_cols = output_var->type->fields.array->matrix_columns; + unsigned actual_array_size = this->is_clip_distance_mesa ? + prog->Vert.ClipDistanceArraySize : output_var->type->array_size(); if (this->is_subscripted) { /* Check array bounds. */ - if (this->array_subscript >= - (unsigned) output_var->type->array_size()) { + if (this->array_subscript >= actual_array_size) { linker_error(prog, "Transform feedback varying %s has index " - "%i, but the array size is %i.", + "%i, but the array size is %u.", this->orig_name, this->array_subscript, - output_var->type->array_size()); + actual_array_size); return false; } - this->location = - output_var->location + this->array_subscript * matrix_cols; + if (this->is_clip_distance_mesa) { + this->location = + output_var->location + this->array_subscript / 4; + } else { + this->location = + output_var->location + this->array_subscript * matrix_cols; + } this->size = 1; } else { this->location = output_var->location; - this->size = (unsigned) output_var->type->array_size(); + this->size = actual_array_size; } this->vector_elements = output_var->type->fields.array->vector_elements; this->matrix_columns = matrix_cols; - this->type = output_var->type->fields.array->gl_type; + if (this->is_clip_distance_mesa) + this->type = GL_FLOAT; + else + this->type = output_var->type->fields.array->gl_type; } else { /* Regular variable (scalar, vector, or matrix) */ if (this->is_subscripted) { @@ -1587,6 +1602,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, this->matrix_columns = output_var->type->matrix_columns; this->type = output_var->type->gl_type; } + /* From GL_EXT_transform_feedback: * A program will fail to link if: * @@ -1615,7 +1631,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, * is returned. */ bool -tfeedback_decl::store(struct gl_shader_program *prog, +tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, unsigned varying) const { @@ -1631,21 +1647,63 @@ tfeedback_decl::store(struct gl_shader_program *prog, this->orig_name); return false; } - for (unsigned index = 0; index < this->size; ++index) { + + /* 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 && + info->BufferStride[buffer] + this->num_components() > + ctx->Const.MaxTransformFeedbackInterleavedComponents) { + linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS " + "limit has been exceeded."); + return false; + } + + /* Verify that the checks on MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS + * and MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS are sufficient to prevent + * overflow of info->Outputs[]. In worst case we generate one entry in + * Outputs[] per component so a conservative check is to verify that the + * size of the array is greater than or equal to both + * MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS and + * MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS. + */ + assert(Elements(info->Outputs) >= + ctx->Const.MaxTransformFeedbackInterleavedComponents); + assert(Elements(info->Outputs) >= + ctx->Const.MaxTransformFeedbackSeparateComponents); + + unsigned translated_size = this->size; + if (this->is_clip_distance_mesa) + translated_size = (translated_size + 3) / 4; + unsigned components_so_far = 0; + for (unsigned index = 0; index < translated_size; ++index) { for (unsigned v = 0; v < this->matrix_columns; ++v) { - unsigned num_components = - this->single_component >= 0 ? 1 : this->vector_elements; + unsigned num_components = this->vector_elements; + info->Outputs[info->NumOutputs].ComponentOffset = 0; + if (this->is_clip_distance_mesa) { + if (this->is_subscripted) { + num_components = 1; + info->Outputs[info->NumOutputs].ComponentOffset = + this->array_subscript % 4; + } else { + num_components = MIN2(4, this->size - components_so_far); + } + } info->Outputs[info->NumOutputs].OutputRegister = this->location + v + index * this->matrix_columns; info->Outputs[info->NumOutputs].NumComponents = num_components; info->Outputs[info->NumOutputs].OutputBuffer = buffer; info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer]; - info->Outputs[info->NumOutputs].ComponentOffset = - this->single_component >= 0 ? this->single_component : 0; ++info->NumOutputs; info->BufferStride[buffer] += num_components; + components_so_far += num_components; } } + assert(components_so_far == this->num_components()); info->Varyings[varying].Name = ralloc_strdup(prog, this->orig_name); info->Varyings[varying].Type = this->type; @@ -1914,7 +1972,6 @@ 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; bool separate_attribs_mode = prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS; @@ -1933,25 +1990,9 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, for (unsigned i = 0; i < num_tfeedback_decls; ++i) { unsigned buffer = separate_attribs_mode ? i : 0; - if (!tfeedback_decls[i].store(prog, &prog->LinkedTransformFeedback, + if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback, buffer, i)) 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; |