From 642e5b413e0890b2070ba78fde42db381eaf02e5 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Wed, 4 Jan 2012 13:57:52 -0800 Subject: [PATCH] mesa: Fix transform feedback of unsubscripted gl_ClipDistance array. On drivers that set gl_shader_compiler_options::LowerClipDistance (for example i965), we need to handle transform feedback of gl_ClipDistance specially, to account for the fact that the hardware represents it as an array of vec4's rather than an array of floats. The previous way this was accounted for (translating the request for gl_ClipDistance[n] to a request for a component of gl_ClipDistanceMESA[n/4]) doesn't work when performing transform feedback on the whole unsubscripted array, because we need to keep track of the size of the gl_ClipDistance array prior to the lowering pass. So I replaced it with a boolean is_clip_distance_mesa, which switches on the special logic that is needed to handle the lowered version of gl_ClipDistance. Fixes Piglit tests "EXT_transform_feedback/builtin-varyings gl_ClipDistance[{1,2,3,5,6,7}]-no-subscript". Reviewed-by: Eric Anholt --- src/glsl/linker.cpp | 89 ++++++++++++++++++++++++++---------------- src/mesa/main/mtypes.h | 2 + 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index f32c2175f59..39a9c466499 100644 --- a/src/glsl/linker.cpp +++ b/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; @@ -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,10 +1418,10 @@ public: */ unsigned num_components() const { - if (this->single_component == -1) - return this->vector_elements * this->matrix_columns * this->size; + if (this->is_clip_distance_mesa) + return this->size; else - return 1; + return this->vector_elements * this->matrix_columns * this->size; } private: @@ -1437,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 @@ -1487,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, '['); @@ -1503,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; @@ -1533,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; } @@ -1555,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) { @@ -1590,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: * @@ -1634,18 +1647,28 @@ tfeedback_decl::store(struct gl_shader_program *prog, this->orig_name); return false; } + 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 < this->size; ++index) { + 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; diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 64d8c8d3f71..bb46ba0c035 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2277,6 +2277,8 @@ struct gl_shader_program /** Vertex shader state - copied into gl_vertex_program at link time */ struct { GLboolean UsesClipDistance; /**< True if gl_ClipDistance is written to. */ + GLuint ClipDistanceArraySize; /**< Size of the gl_ClipDistance array, or + 0 if not present. */ } Vert; /* post-link info: */ -- 2.30.2