diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/glsl_types.cpp | 29 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_types.h | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniforms.cpp | 60 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 143 |
4 files changed, 185 insertions, 53 deletions
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 8587da0a3..d4385a644 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -127,6 +127,35 @@ glsl_type::contains_sampler() const } } +gl_texture_index +glsl_type::sampler_index() const +{ + const glsl_type *const t = (this->is_array()) ? this->fields.array : this; + + assert(t->is_sampler()); + + switch (t->sampler_dimensionality) { + case GLSL_SAMPLER_DIM_1D: + return (t->sampler_array) ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX; + case GLSL_SAMPLER_DIM_2D: + return (t->sampler_array) ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX; + case GLSL_SAMPLER_DIM_3D: + return TEXTURE_3D_INDEX; + case GLSL_SAMPLER_DIM_CUBE: + return TEXTURE_CUBE_INDEX; + case GLSL_SAMPLER_DIM_RECT: + return TEXTURE_RECT_INDEX; + case GLSL_SAMPLER_DIM_BUF: + assert(!"FINISHME: Implement ARB_texture_buffer_object"); + break; + case GLSL_SAMPLER_DIM_EXTERNAL: + return TEXTURE_EXTERNAL_INDEX; + default: + assert(!"Should not get here."); + break; + } +} + void glsl_type::generate_100ES_types(glsl_symbol_table *symtab) { diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index 4ac90118b..2997c9311 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -28,6 +28,7 @@ #include <string.h> #include <assert.h> +#include "main/mtypes.h" /* for gl_texture_index, C++'s enum rules are broken */ #ifdef __cplusplus extern "C" { @@ -354,6 +355,11 @@ struct glsl_type { bool contains_sampler() const; /** + * Get the Mesa texture target index for a sampler type. + */ + gl_texture_index sampler_index() const; + + /** * Query whether or not a type is an array */ bool is_array() const diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index 087651bd0..0b8a02d4e 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -209,7 +209,13 @@ public: union gl_constant_value *values) : map(map), uniforms(uniforms), next_sampler(0), values(values) { - /* empty */ + memset(this->targets, 0, sizeof(this->targets)); + } + + void start_shader() + { + this->shader_samplers_used = 0; + this->shader_shadow_samplers = 0; } private: @@ -230,8 +236,25 @@ private: * example, we may be processing the uniform in the fragment shader, but * the uniform was already processed in the vertex shader. */ - if (this->uniforms[id].storage != NULL) + if (this->uniforms[id].storage != NULL) { + /* If the uniform already has storage set from another shader stage, + * mark the samplers used for this shader stage. + */ + if (type->contains_sampler()) { + const unsigned count = MAX2(1, this->uniforms[id].array_elements); + const unsigned shadow = (type->is_array()) + ? type->fields.array->sampler_shadow : type->sampler_shadow; + + for (unsigned i = 0; i < count; i++) { + const unsigned s = this->uniforms[id].sampler + i; + + this->shader_samplers_used |= 1U << s; + this->shader_shadow_samplers |= shadow << s; + } + } + return; + } const glsl_type *base_type; if (type->is_array()) { @@ -249,6 +272,17 @@ private: * array elements for arrays. */ this->next_sampler += MAX2(1, this->uniforms[id].array_elements); + + const gl_texture_index target = base_type->sampler_index(); + const unsigned shadow = base_type->sampler_shadow; + for (unsigned i = this->uniforms[id].sampler + ; i < this->next_sampler + ; i++) { + this->targets[i] = target; + this->shader_samplers_used |= 1U << i; + this->shader_shadow_samplers |= shadow << i; + } + } else { this->uniforms[id].sampler = ~0; } @@ -270,6 +304,18 @@ private: public: union gl_constant_value *values; + + gl_texture_index targets[MAX_SAMPLERS]; + + /** + * Mask of samplers used by the current shader stage. + */ + unsigned shader_samplers_used; + + /** + * Mask of samplers used by the current shader stage for shadows. + */ + unsigned shader_shadow_samplers; }; void @@ -346,6 +392,10 @@ link_assign_uniform_locations(struct gl_shader_program *prog) if (prog->_LinkedShaders[i] == NULL) continue; + /* Reset various per-shader target counts. + */ + parcel.start_shader(); + foreach_list(node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); @@ -359,8 +409,14 @@ link_assign_uniform_locations(struct gl_shader_program *prog) parcel.process(var); } + + prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used; + prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers; } + assert(sizeof(prog->SamplerTargets) == sizeof(parcel.targets)); + memcpy(prog->SamplerTargets, parcel.targets, sizeof(prog->SamplerTargets)); + #ifndef NDEBUG for (unsigned i = 0; i < num_user_uniforms; i++) { assert(uniforms[i].storage != NULL); 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; |