X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=inline;f=src%2Fglsl%2Flinker.cpp;h=ae628cd86bd9844b71e27b74ccddb42646cb45b2;hb=7a1735680007a78b0a56107871e4afdc33985604;hp=d9527d4ba2b6f142dbf8d3fab35a00e5ba32c881;hpb=ccaf37f4496eb836866c9daacf21f1f5ac8c6d66;p=mesa.git diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index d9527d4ba2b..ae628cd86bd 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -65,6 +65,7 @@ */ #include +#include "util/strndup.h" #include "main/core.h" #include "glsl_symbol_table.h" #include "glsl_parser_extras.h" @@ -250,6 +251,144 @@ public: } }; +class tess_eval_array_resize_visitor : public ir_hierarchical_visitor { +public: + unsigned num_vertices; + gl_shader_program *prog; + + tess_eval_array_resize_visitor(unsigned num_vertices, gl_shader_program *prog) + { + this->num_vertices = num_vertices; + this->prog = prog; + } + + virtual ~tess_eval_array_resize_visitor() + { + /* empty */ + } + + virtual ir_visitor_status visit(ir_variable *var) + { + if (!var->type->is_array() || var->data.mode != ir_var_shader_in || var->data.patch) + return visit_continue; + + var->type = glsl_type::get_array_instance(var->type->fields.array, + this->num_vertices); + var->data.max_array_access = this->num_vertices - 1; + + return visit_continue; + } + + /* Dereferences of input variables need to be updated so that their type + * matches the newly assigned type of the variable they are accessing. */ + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + ir->type = ir->var->type; + return visit_continue; + } + + /* Dereferences of 2D input arrays need to be updated so that their type + * matches the newly assigned type of the array they are accessing. */ + virtual ir_visitor_status visit_leave(ir_dereference_array *ir) + { + const glsl_type *const vt = ir->array->type; + if (vt->is_array()) + ir->type = vt->fields.array; + return visit_continue; + } +}; + +class barrier_use_visitor : public ir_hierarchical_visitor { +public: + barrier_use_visitor(gl_shader_program *prog) + : prog(prog), in_main(false), after_return(false), control_flow(0) + { + } + + virtual ~barrier_use_visitor() + { + /* empty */ + } + + virtual ir_visitor_status visit_enter(ir_function *ir) + { + if (strcmp(ir->name, "main") == 0) + in_main = true; + + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_function *) + { + in_main = false; + after_return = false; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_return *) + { + after_return = true; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_if *) + { + ++control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_if *) + { + --control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_loop *) + { + ++control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_loop *) + { + --control_flow; + return visit_continue; + } + + /* FINISHME: `switch` is not expressed at the IR level -- it's already + * been lowered to a mess of `if`s. We'll correctly disallow any use of + * barrier() in a conditional path within the switch, but not in a path + * which is always hit. + */ + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + if (ir->use_builtin && strcmp(ir->callee_name(), "barrier") == 0) { + /* Use of barrier(); determine if it is legal: */ + if (!in_main) { + linker_error(prog, "Builtin barrier() may only be used in main"); + return visit_stop; + } + + if (after_return) { + linker_error(prog, "Builtin barrier() may not be used after return"); + return visit_stop; + } + + if (control_flow != 0) { + linker_error(prog, "Builtin barrier() may not be used inside control flow"); + return visit_stop; + } + } + return visit_continue; + } + +private: + gl_shader_program *prog; + bool in_main, after_return; + int control_flow; +}; + /** * Visitor that determines the highest stream id to which a (geometry) shader * emits vertices. It also checks whether End{Stream}Primitive is ever called. @@ -462,6 +601,10 @@ parse_program_resource_name(const GLchar *name, if (array_index < 0) return -1; + /* Check for leading zero */ + if (name[i] == '0' && name[i+1] != ']') + return -1; + *out_base_name_end = name + (i - 1); return array_index; } @@ -488,27 +631,19 @@ link_invalidate_variable_locations(exec_list *ir) /* ir_variable::is_unmatched_generic_inout is used by the linker while * connecting outputs from one stage to inputs of the next stage. - * - * There are two implicit assumptions here. First, we assume that any - * built-in variable (i.e., non-generic in or out) will have - * explicit_location set. Second, we assume that any generic in or out - * will not have explicit_location set. - * - * This second assumption will only be valid until - * GL_ARB_separate_shader_objects is supported. When that extension is - * implemented, this function will need some modifications. */ - if (!var->data.explicit_location) { - var->data.is_unmatched_generic_inout = 1; - } else { + if (var->data.explicit_location && + var->data.location < VARYING_SLOT_VAR0) { var->data.is_unmatched_generic_inout = 0; + } else { + var->data.is_unmatched_generic_inout = 1; } } } /** - * Set UsesClipDistance and ClipDistanceArraySize based on the given shader. + * Set clip_distance_array_size based on the given shader. * * Also check for errors based on incorrect usage of gl_ClipVertex and * gl_ClipDistance. @@ -517,10 +652,10 @@ link_invalidate_variable_locations(exec_list *ir) */ static void analyze_clip_usage(struct gl_shader_program *prog, - struct gl_shader *shader, GLboolean *UsesClipDistance, - GLuint *ClipDistanceArraySize) + struct gl_shader *shader, + GLuint *clip_distance_array_size) { - *ClipDistanceArraySize = 0; + *clip_distance_array_size = 0; if (!prog->IsES && prog->Version >= 130) { /* From section 7.1 (Vertex Shader Special Variables) of the @@ -543,13 +678,14 @@ analyze_clip_usage(struct gl_shader_program *prog, _mesa_shader_stage_to_string(shader->Stage)); return; } - *UsesClipDistance = clip_distance.variable_found(); - ir_variable *clip_distance_var = - shader->symbols->get_variable("gl_ClipDistance"); - if (clip_distance_var) - *ClipDistanceArraySize = clip_distance_var->type->length; - } else { - *UsesClipDistance = false; + + if (clip_distance.variable_found()) { + ir_variable *clip_distance_var = + shader->symbols->get_variable("gl_ClipDistance"); + + assert(clip_distance_var); + *clip_distance_array_size = clip_distance_var->type->length; + } } } @@ -557,8 +693,7 @@ analyze_clip_usage(struct gl_shader_program *prog, /** * Verify that a vertex shader executable meets all semantic requirements. * - * Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize - * as a side effect. + * Also sets prog->Vert.ClipDistanceArraySize as a side effect. * * \param shader Vertex shader executable to be verified */ @@ -611,8 +746,17 @@ validate_vertex_shader_executable(struct gl_shader_program *prog, } } - analyze_clip_usage(prog, shader, &prog->Vert.UsesClipDistance, - &prog->Vert.ClipDistanceArraySize); + analyze_clip_usage(prog, shader, &prog->Vert.ClipDistanceArraySize); +} + +void +validate_tess_eval_shader_executable(struct gl_shader_program *prog, + struct gl_shader *shader) +{ + if (shader == NULL) + return; + + analyze_clip_usage(prog, shader, &prog->TessEval.ClipDistanceArraySize); } @@ -643,8 +787,8 @@ validate_fragment_shader_executable(struct gl_shader_program *prog, /** * Verify that a geometry shader executable meets all semantic requirements * - * Also sets prog->Geom.VerticesIn, prog->Geom.UsesClipDistance, and - * prog->Geom.ClipDistanceArraySize as a side effect. + * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize as + * a side effect. * * \param shader Geometry shader executable to be verified */ @@ -658,8 +802,7 @@ validate_geometry_shader_executable(struct gl_shader_program *prog, unsigned num_vertices = vertices_per_prim(prog->Geom.InputType); prog->Geom.VerticesIn = num_vertices; - analyze_clip_usage(prog, shader, &prog->Geom.UsesClipDistance, - &prog->Geom.ClipDistanceArraySize); + analyze_clip_usage(prog, shader, &prog->Geom.ClipDistanceArraySize); } /** @@ -724,30 +867,40 @@ validate_intrastage_arrays(struct gl_shader_program *prog, * In addition, set the type of the linked variable to the * explicitly sized array. */ - if (var->type->is_array() && existing->type->is_array() && - (var->type->fields.array == existing->type->fields.array) && - ((var->type->length == 0)|| (existing->type->length == 0))) { - if (var->type->length != 0) { - if (var->type->length <= existing->data.max_array_access) { - linker_error(prog, "%s `%s' declared as type " - "`%s' but outermost dimension has an index" - " of `%i'\n", - mode_string(var), - var->name, var->type->name, - existing->data.max_array_access); - } - existing->type = var->type; - return true; - } else if (existing->type->length != 0) { - if(existing->type->length <= var->data.max_array_access) { - linker_error(prog, "%s `%s' declared as type " - "`%s' but outermost dimension has an index" - " of `%i'\n", - mode_string(var), - var->name, existing->type->name, - var->data.max_array_access); + if (var->type->is_array() && existing->type->is_array()) { + if ((var->type->fields.array == existing->type->fields.array) && + ((var->type->length == 0)|| (existing->type->length == 0))) { + if (var->type->length != 0) { + if (var->type->length <= existing->data.max_array_access) { + linker_error(prog, "%s `%s' declared as type " + "`%s' but outermost dimension has an index" + " of `%i'\n", + mode_string(var), + var->name, var->type->name, + existing->data.max_array_access); + } + existing->type = var->type; + return true; + } else if (existing->type->length != 0) { + if(existing->type->length <= var->data.max_array_access && + !existing->data.from_ssbo_unsized_array) { + linker_error(prog, "%s `%s' declared as type " + "`%s' but outermost dimension has an index" + " of `%i'\n", + mode_string(var), + var->name, existing->type->name, + var->data.max_array_access); + } + return true; } - return true; + } else { + /* The arrays of structs could have different glsl_type pointers but + * they are actually the same type. Use record_compare() to check that. + */ + if (existing->type->fields.array->is_record() && + var->type->fields.array->is_record() && + existing->type->fields.array->record_compare(var->type->fields.array)) + return true; } } return false; @@ -777,9 +930,13 @@ cross_validate_globals(struct gl_shader_program *prog, if (var == NULL) continue; - if (uniforms_only && (var->data.mode != ir_var_uniform)) + if (uniforms_only && (var->data.mode != ir_var_uniform && var->data.mode != ir_var_shader_storage)) continue; + /* don't cross validate subroutine uniforms */ + if (var->type->contains_subroutine()) + continue; + /* Don't cross validate temporaries that are at global scope. These * will eventually get pulled into the shaders 'main'. */ @@ -802,12 +959,24 @@ cross_validate_globals(struct gl_shader_program *prog, && existing->type->record_compare(var->type)) { existing->type = var->type; } else { - linker_error(prog, "%s `%s' declared as type " - "`%s' and type `%s'\n", - mode_string(var), - var->name, var->type->name, - existing->type->name); - return; + /* If it is an unsized array in a Shader Storage Block, + * two different shaders can access to different elements. + * Because of that, they might be converted to different + * sized arrays, then check that they are compatible but + * ignore the array size. + */ + if (!(var->data.mode == ir_var_shader_storage && + var->data.from_ssbo_unsized_array && + existing->data.mode == ir_var_shader_storage && + existing->data.from_ssbo_unsized_array && + var->type->gl_type == existing->type->gl_type)) { + linker_error(prog, "%s `%s' declared as type " + "`%s' and type `%s'\n", + mode_string(var), + var->name, var->type->name, + existing->type->name); + return; + } } } } @@ -982,7 +1151,7 @@ cross_validate_uniforms(struct gl_shader_program *prog) } /** - * Accumulates the array of prog->UniformBlocks and checks that all + * Accumulates the array of prog->BufferInterfaceBlocks and checks that all * definitons of blocks agree on their contents. */ static bool @@ -991,33 +1160,33 @@ interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog) unsigned max_num_uniform_blocks = 0; for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { if (prog->_LinkedShaders[i]) - max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks; + max_num_uniform_blocks += prog->_LinkedShaders[i]->NumBufferInterfaceBlocks; } for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { struct gl_shader *sh = prog->_LinkedShaders[i]; - prog->UniformBlockStageIndex[i] = ralloc_array(prog, int, - max_num_uniform_blocks); + prog->InterfaceBlockStageIndex[i] = ralloc_array(prog, int, + max_num_uniform_blocks); for (unsigned int j = 0; j < max_num_uniform_blocks; j++) - prog->UniformBlockStageIndex[i][j] = -1; + prog->InterfaceBlockStageIndex[i][j] = -1; if (sh == NULL) continue; - for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) { + for (unsigned int j = 0; j < sh->NumBufferInterfaceBlocks; j++) { int index = link_cross_validate_uniform_block(prog, - &prog->UniformBlocks, - &prog->NumUniformBlocks, - &sh->UniformBlocks[j]); + &prog->BufferInterfaceBlocks, + &prog->NumBufferInterfaceBlocks, + &sh->BufferInterfaceBlocks[j]); if (index == -1) { linker_error(prog, "uniform block `%s' has mismatching definitions\n", - sh->UniformBlocks[j].Name); + sh->BufferInterfaceBlocks[j].Name); return false; } - prog->UniformBlockStageIndex[i][index] = j; + prog->InterfaceBlockStageIndex[i][index] = j; } } @@ -1184,33 +1353,6 @@ move_non_declarations(exec_list *instructions, exec_node *last, return last; } -/** - * Get the function signature for main from a shader - */ -ir_function_signature * -link_get_main_function_signature(gl_shader *sh) -{ - ir_function *const f = sh->symbols->get_function("main"); - if (f != NULL) { - exec_list void_parameters; - - /* Look for the 'void main()' signature and ensure that it's defined. - * This keeps the linker from accidentally pick a shader that just - * contains a prototype for main. - * - * We don't have to check for multiple definitions of main (in multiple - * shaders) because that would have already been caught above. - */ - ir_function_signature *sig = - f->matching_signature(NULL, &void_parameters, false); - if ((sig != NULL) && sig->is_defined) { - return sig; - } - } - - return NULL; -} - /** * This class is only used in link_intrastage_shaders() below but declaring @@ -1234,24 +1376,27 @@ public: virtual ir_visitor_status visit(ir_variable *var) { - fixup_type(&var->type, var->data.max_array_access); + const glsl_type *type_without_array; + fixup_type(&var->type, var->data.max_array_access, + var->data.from_ssbo_unsized_array); + type_without_array = var->type->without_array(); if (var->type->is_interface()) { if (interface_contains_unsized_arrays(var->type)) { const glsl_type *new_type = resize_interface_members(var->type, - var->get_max_ifc_array_access()); + var->get_max_ifc_array_access(), + var->is_in_shader_storage_block()); var->type = new_type; var->change_interface_type(new_type); } - } else if (var->type->is_array() && - var->type->fields.array->is_interface()) { - if (interface_contains_unsized_arrays(var->type->fields.array)) { + } else if (type_without_array->is_interface()) { + if (interface_contains_unsized_arrays(type_without_array)) { const glsl_type *new_type = - resize_interface_members(var->type->fields.array, - var->get_max_ifc_array_access()); + resize_interface_members(type_without_array, + var->get_max_ifc_array_access(), + var->is_in_shader_storage_block()); var->change_interface_type(new_type); - var->type = - glsl_type::get_array_instance(new_type, var->type->length); + var->type = update_interface_members_array(var->type, new_type); } } else if (const glsl_type *ifc_type = var->get_interface_type()) { /* Store a pointer to the variable in the unnamed_interfaces @@ -1290,15 +1435,31 @@ private: * If the type pointed to by \c type represents an unsized array, replace * it with a sized array whose size is determined by max_array_access. */ - static void fixup_type(const glsl_type **type, unsigned max_array_access) + static void fixup_type(const glsl_type **type, unsigned max_array_access, + bool from_ssbo_unsized_array) { - if ((*type)->is_unsized_array()) { + if (!from_ssbo_unsized_array && (*type)->is_unsized_array()) { *type = glsl_type::get_array_instance((*type)->fields.array, max_array_access + 1); assert(*type != NULL); } } + static const glsl_type * + update_interface_members_array(const glsl_type *type, + const glsl_type *new_interface_type) + { + const glsl_type *element_type = type->fields.array; + if (element_type->is_array()) { + const glsl_type *new_array_type = + update_interface_members_array(element_type, new_interface_type); + return glsl_type::get_array_instance(new_array_type, type->length); + } else { + return glsl_type::get_array_instance(new_interface_type, + type->length); + } + } + /** * Determine whether the given interface type contains unsized arrays (if * it doesn't, array_sizing_visitor doesn't need to process it). @@ -1320,14 +1481,23 @@ private: */ static const glsl_type * resize_interface_members(const glsl_type *type, - const unsigned *max_ifc_array_access) + const unsigned *max_ifc_array_access, + bool is_ssbo) { unsigned num_fields = type->length; glsl_struct_field *fields = new glsl_struct_field[num_fields]; memcpy(fields, type->fields.structure, num_fields * sizeof(*fields)); for (unsigned i = 0; i < num_fields; i++) { - fixup_type(&fields[i].type, max_ifc_array_access[i]); + /* If SSBO last member is unsized array, we don't replace it by a sized + * array. + */ + if (is_ssbo && i == (num_fields - 1)) + fixup_type(&fields[i].type, max_ifc_array_access[i], + true); + else + fixup_type(&fields[i].type, max_ifc_array_access[i], + false); } glsl_interface_packing packing = (glsl_interface_packing) type->interface_packing; @@ -1383,6 +1553,167 @@ private: hash_table *unnamed_interfaces; }; + +/** + * Performs the cross-validation of tessellation control shader vertices and + * layout qualifiers for the attached tessellation control shaders, + * and propagates them to the linked TCS and linked shader program. + */ +static void +link_tcs_out_layout_qualifiers(struct gl_shader_program *prog, + struct gl_shader *linked_shader, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + linked_shader->TessCtrl.VerticesOut = 0; + + if (linked_shader->Stage != MESA_SHADER_TESS_CTRL) + return; + + /* From the GLSL 4.0 spec (chapter 4.3.8.2): + * + * "All tessellation control shader layout declarations in a program + * must specify the same output patch vertex count. There must be at + * least one layout qualifier specifying an output patch vertex count + * in any program containing tessellation control shaders; however, + * such a declaration is not required in all tessellation control + * shaders." + */ + + for (unsigned i = 0; i < num_shaders; i++) { + struct gl_shader *shader = shader_list[i]; + + if (shader->TessCtrl.VerticesOut != 0) { + if (linked_shader->TessCtrl.VerticesOut != 0 && + linked_shader->TessCtrl.VerticesOut != shader->TessCtrl.VerticesOut) { + linker_error(prog, "tessellation control shader defined with " + "conflicting output vertex count (%d and %d)\n", + linked_shader->TessCtrl.VerticesOut, + shader->TessCtrl.VerticesOut); + return; + } + linked_shader->TessCtrl.VerticesOut = shader->TessCtrl.VerticesOut; + } + } + + /* Just do the intrastage -> interstage propagation right now, + * since we already know we're in the right type of shader program + * for doing it. + */ + if (linked_shader->TessCtrl.VerticesOut == 0) { + linker_error(prog, "tessellation control shader didn't declare " + "vertices out layout qualifier\n"); + return; + } + prog->TessCtrl.VerticesOut = linked_shader->TessCtrl.VerticesOut; +} + + +/** + * Performs the cross-validation of tessellation evaluation shader + * primitive type, vertex spacing, ordering and point_mode layout qualifiers + * for the attached tessellation evaluation shaders, and propagates them + * to the linked TES and linked shader program. + */ +static void +link_tes_in_layout_qualifiers(struct gl_shader_program *prog, + struct gl_shader *linked_shader, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + linked_shader->TessEval.PrimitiveMode = PRIM_UNKNOWN; + linked_shader->TessEval.Spacing = 0; + linked_shader->TessEval.VertexOrder = 0; + linked_shader->TessEval.PointMode = -1; + + if (linked_shader->Stage != MESA_SHADER_TESS_EVAL) + return; + + /* From the GLSL 4.0 spec (chapter 4.3.8.1): + * + * "At least one tessellation evaluation shader (compilation unit) in + * a program must declare a primitive mode in its input layout. + * Declaration vertex spacing, ordering, and point mode identifiers is + * optional. It is not required that all tessellation evaluation + * shaders in a program declare a primitive mode. If spacing or + * vertex ordering declarations are omitted, the tessellation + * primitive generator will use equal spacing or counter-clockwise + * vertex ordering, respectively. If a point mode declaration is + * omitted, the tessellation primitive generator will produce lines or + * triangles according to the primitive mode." + */ + + for (unsigned i = 0; i < num_shaders; i++) { + struct gl_shader *shader = shader_list[i]; + + if (shader->TessEval.PrimitiveMode != PRIM_UNKNOWN) { + if (linked_shader->TessEval.PrimitiveMode != PRIM_UNKNOWN && + linked_shader->TessEval.PrimitiveMode != shader->TessEval.PrimitiveMode) { + linker_error(prog, "tessellation evaluation shader defined with " + "conflicting input primitive modes.\n"); + return; + } + linked_shader->TessEval.PrimitiveMode = shader->TessEval.PrimitiveMode; + } + + if (shader->TessEval.Spacing != 0) { + if (linked_shader->TessEval.Spacing != 0 && + linked_shader->TessEval.Spacing != shader->TessEval.Spacing) { + linker_error(prog, "tessellation evaluation shader defined with " + "conflicting vertex spacing.\n"); + return; + } + linked_shader->TessEval.Spacing = shader->TessEval.Spacing; + } + + if (shader->TessEval.VertexOrder != 0) { + if (linked_shader->TessEval.VertexOrder != 0 && + linked_shader->TessEval.VertexOrder != shader->TessEval.VertexOrder) { + linker_error(prog, "tessellation evaluation shader defined with " + "conflicting ordering.\n"); + return; + } + linked_shader->TessEval.VertexOrder = shader->TessEval.VertexOrder; + } + + if (shader->TessEval.PointMode != -1) { + if (linked_shader->TessEval.PointMode != -1 && + linked_shader->TessEval.PointMode != shader->TessEval.PointMode) { + linker_error(prog, "tessellation evaluation shader defined with " + "conflicting point modes.\n"); + return; + } + linked_shader->TessEval.PointMode = shader->TessEval.PointMode; + } + + } + + /* Just do the intrastage -> interstage propagation right now, + * since we already know we're in the right type of shader program + * for doing it. + */ + if (linked_shader->TessEval.PrimitiveMode == PRIM_UNKNOWN) { + linker_error(prog, + "tessellation evaluation shader didn't declare input " + "primitive modes.\n"); + return; + } + prog->TessEval.PrimitiveMode = linked_shader->TessEval.PrimitiveMode; + + if (linked_shader->TessEval.Spacing == 0) + linked_shader->TessEval.Spacing = GL_EQUAL; + prog->TessEval.Spacing = linked_shader->TessEval.Spacing; + + if (linked_shader->TessEval.VertexOrder == 0) + linked_shader->TessEval.VertexOrder = GL_CCW; + prog->TessEval.VertexOrder = linked_shader->TessEval.VertexOrder; + + if (linked_shader->TessEval.PointMode == -1) + linked_shader->TessEval.PointMode = GL_FALSE; + prog->TessEval.PointMode = linked_shader->TessEval.PointMode; +} + + /** * Performs the cross-validation of layout qualifiers specified in * redeclaration of gl_FragCoord for the attached fragment shaders, @@ -1656,7 +1987,7 @@ link_intrastage_shaders(void *mem_ctx, /* Link up uniform blocks defined within this stage. */ const unsigned num_uniform_blocks = - link_uniform_blocks(mem_ctx, prog, shader_list, num_shaders, + link_uniform_blocks(mem_ctx, ctx, prog, shader_list, num_shaders, &uniform_blocks); if (!prog->LinkStatus) return NULL; @@ -1708,7 +2039,7 @@ link_intrastage_shaders(void *mem_ctx, */ gl_shader *main = NULL; for (unsigned i = 0; i < num_shaders; i++) { - if (link_get_main_function_signature(shader_list[i]) != NULL) { + if (_mesa_get_main_function_signature(shader_list[i]) != NULL) { main = shader_list[i]; break; } @@ -1724,11 +2055,13 @@ link_intrastage_shaders(void *mem_ctx, linked->ir = new(linked) exec_list; clone_ir_list(mem_ctx, linked->ir, main->ir); - linked->UniformBlocks = uniform_blocks; - linked->NumUniformBlocks = num_uniform_blocks; - ralloc_steal(linked, linked->UniformBlocks); + linked->BufferInterfaceBlocks = uniform_blocks; + linked->NumBufferInterfaceBlocks = num_uniform_blocks; + ralloc_steal(linked, linked->BufferInterfaceBlocks); link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); + link_tcs_out_layout_qualifiers(prog, linked, shader_list, num_shaders); + link_tes_in_layout_qualifiers(prog, linked, shader_list, num_shaders); link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders); link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); @@ -1738,7 +2071,7 @@ link_intrastage_shaders(void *mem_ctx, * copy of the original shader that contained the main function). */ ir_function_signature *const main_sig = - link_get_main_function_signature(linked); + _mesa_get_main_function_signature(linked); /* Move any instructions other than variable declarations or function * declarations into main. @@ -1790,7 +2123,7 @@ link_intrastage_shaders(void *mem_ctx, if (!ok) { - ctx->Driver.DeleteShader(ctx, linked); + _mesa_delete_shader(ctx, linked); return NULL; } @@ -1811,6 +2144,14 @@ link_intrastage_shaders(void *mem_ctx, if (ctx->Const.VertexID_is_zero_based) lower_vertex_id(linked); + /* Validate correct usage of barrier() in the tess control shader */ + if (linked->Stage == MESA_SHADER_TESS_CTRL) { + barrier_use_visitor visitor(prog); + foreach_in_list(ir_instruction, ir, linked->ir) { + ir->accept(&visitor); + } + } + /* Make a pass over all variable declarations to ensure that arrays with * unspecified sizes have a size specified. The size is inferred from the * max_array_access field. @@ -1858,8 +2199,11 @@ update_array_sizes(struct gl_shader_program *prog) * Atomic counters are supposed to get deterministic * locations assigned based on the declaration ordering and * sizes, array compaction would mess that up. + * + * Subroutine uniforms are not removed. */ - if (var->is_in_uniform_block() || var->type->contains_atomic()) + if (var->is_in_buffer_block() || var->type->contains_atomic() || + var->type->contains_subroutine()) continue; unsigned int size = var->data.max_array_access; @@ -1904,6 +2248,50 @@ update_array_sizes(struct gl_shader_program *prog) } } +/** + * Resize tessellation evaluation per-vertex inputs to the size of + * tessellation control per-vertex outputs. + */ +static void +resize_tes_inputs(struct gl_context *ctx, + struct gl_shader_program *prog) +{ + if (prog->_LinkedShaders[MESA_SHADER_TESS_EVAL] == NULL) + return; + + gl_shader *const tcs = prog->_LinkedShaders[MESA_SHADER_TESS_CTRL]; + gl_shader *const tes = prog->_LinkedShaders[MESA_SHADER_TESS_EVAL]; + + /* If no control shader is present, then the TES inputs are statically + * sized to MaxPatchVertices; the actual size of the arrays won't be + * known until draw time. + */ + const int num_vertices = tcs + ? tcs->TessCtrl.VerticesOut + : ctx->Const.MaxPatchVertices; + + tess_eval_array_resize_visitor input_resize_visitor(num_vertices, prog); + foreach_in_list(ir_instruction, ir, tes->ir) { + ir->accept(&input_resize_visitor); + } + + if (tcs) { + /* Convert the gl_PatchVerticesIn system value into a constant, since + * the value is known at this point. + */ + foreach_in_list(ir_instruction, ir, tes->ir) { + ir_variable *var = ir->as_variable(); + if (var && var->data.mode == ir_var_system_value && + var->data.location == SYSTEM_VALUE_VERTICES_IN) { + void *mem_ctx = ralloc_parent(var); + var->data.mode = ir_var_auto; + var->data.location = 0; + var->constant_value = new(mem_ctx) ir_constant(num_vertices); + } + } + } +} + /** * Find a contiguous set of available bits in a bitmask. * @@ -1940,12 +2328,10 @@ find_available_slots(unsigned used_mask, unsigned needed_count) * Assign locations for either VS inputs or FS outputs * * \param prog Shader program whose variables need locations assigned + * \param constants Driver specific constant values for the program. * \param target_index Selector for the program target to receive location * assignmnets. Must be either \c MESA_SHADER_VERTEX or * \c MESA_SHADER_FRAGMENT. - * \param max_index Maximum number of generic locations. This corresponds - * to either the maximum number of draw buffers or the - * maximum number of generic attributes. * * \return * If locations are successfully assigned, true is returned. Otherwise an @@ -1953,13 +2339,22 @@ find_available_slots(unsigned used_mask, unsigned needed_count) */ bool assign_attribute_or_color_locations(gl_shader_program *prog, - unsigned target_index, - unsigned max_index) + struct gl_constants *constants, + unsigned target_index) { + /* Maximum number of generic locations. This corresponds to either the + * maximum number of draw buffers or the maximum number of generic + * attributes. + */ + unsigned max_index = (target_index == MESA_SHADER_VERTEX) ? + constants->Program[target_index].MaxAttribs : + MAX2(constants->MaxDrawBuffers, constants->MaxDualSourceDrawBuffers); + /* Mark invalid locations as being used. */ unsigned used_locations = (max_index >= 32) ? ~0 : ~((1 << max_index) - 1); + unsigned double_storage_locations = 0; assert((target_index == MESA_SHADER_VERTEX) || (target_index == MESA_SHADER_FRAGMENT)); @@ -2010,7 +2405,6 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } to_assign[16]; unsigned num_attr = 0; - unsigned total_attribs_size = 0; foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *const var = node->as_variable(); @@ -2019,6 +2413,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog, continue; if (var->data.explicit_location) { + var->data.is_unmatched_generic_inout = 0; if ((var->data.location >= (int)(max_index + generic_base)) || (var->data.location < 0)) { linker_error(prog, @@ -2052,36 +2447,27 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } } - const unsigned slots = var->type->count_attribute_slots(); - - /* From GL4.5 core spec, section 11.1.1 (Vertex Attributes): + /* From GL4.5 core spec, section 15.2 (Shader Execution): * - * "A program with more than the value of MAX_VERTEX_ATTRIBS active - * attribute variables may fail to link, unless device-dependent - * optimizations are able to make the program fit within available - * hardware resources. For the purposes of this test, attribute variables - * of the type dvec3, dvec4, dmat2x3, dmat2x4, dmat3, dmat3x4, dmat4x3, - * and dmat4 may count as consuming twice as many attributes as equivalent - * single-precision types. While these types use the same number of - * generic attributes as their single-precision equivalents, - * implementations are permitted to consume two single-precision vectors - * of internal storage for each three- or four-component double-precision - * vector." - * Until someone has a good reason in Mesa, enforce that now. + * "Output binding assignments will cause LinkProgram to fail: + * ... + * If the program has an active output assigned to a location greater + * than or equal to the value of MAX_DUAL_SOURCE_DRAW_BUFFERS and has + * an active output assigned an index greater than or equal to one;" */ - if (target_index == MESA_SHADER_VERTEX) { - total_attribs_size += slots; - if (var->type->without_array() == glsl_type::dvec3_type || - var->type->without_array() == glsl_type::dvec4_type || - var->type->without_array() == glsl_type::dmat2x3_type || - var->type->without_array() == glsl_type::dmat2x4_type || - var->type->without_array() == glsl_type::dmat3_type || - var->type->without_array() == glsl_type::dmat3x4_type || - var->type->without_array() == glsl_type::dmat4x3_type || - var->type->without_array() == glsl_type::dmat4_type) - total_attribs_size += slots; + if (target_index == MESA_SHADER_FRAGMENT && var->data.index >= 1 && + var->data.location - generic_base >= + (int) constants->MaxDualSourceDrawBuffers) { + linker_error(prog, + "output location %d >= GL_MAX_DUAL_SOURCE_DRAW_BUFFERS " + "with index %u for %s\n", + var->data.location - generic_base, var->data.index, + var->name); + return false; } + const unsigned slots = var->type->count_attribute_slots(); + /* If the variable is not a built-in and has a location statically * assigned in the shader (presumably via a layout qualifier), make sure * that it doesn't collide with other assigned locations. Otherwise, @@ -2196,9 +2582,41 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } used_locations |= (use_mask << attr); - } - continue; + /* From the GL 4.5 core spec, section 11.1.1 (Vertex Attributes): + * + * "A program with more than the value of MAX_VERTEX_ATTRIBS + * active attribute variables may fail to link, unless + * device-dependent optimizations are able to make the program + * fit within available hardware resources. For the purposes + * of this test, attribute variables of the type dvec3, dvec4, + * dmat2x3, dmat2x4, dmat3, dmat3x4, dmat4x3, and dmat4 may + * count as consuming twice as many attributes as equivalent + * single-precision types. While these types use the same number + * of generic attributes as their single-precision equivalents, + * implementations are permitted to consume two single-precision + * vectors of internal storage for each three- or four-component + * double-precision vector." + * + * Mark this attribute slot as taking up twice as much space + * so we can count it properly against limits. According to + * issue (3) of the GL_ARB_vertex_attrib_64bit behavior, this + * is optional behavior, but it seems preferable. + */ + const glsl_type *type = var->type->without_array(); + if (type == glsl_type::dvec3_type || + type == glsl_type::dvec4_type || + type == glsl_type::dmat2x3_type || + type == glsl_type::dmat2x4_type || + type == glsl_type::dmat3_type || + type == glsl_type::dmat3x4_type || + type == glsl_type::dmat4x3_type || + type == glsl_type::dmat4_type) { + double_storage_locations |= (use_mask << attr); + } + } + + continue; } to_assign[num_attr].slots = slots; @@ -2207,6 +2625,9 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } if (target_index == MESA_SHADER_VERTEX) { + unsigned total_attribs_size = + _mesa_bitcount(used_locations & ((1 << max_index) - 1)) + + _mesa_bitcount(double_storage_locations); if (total_attribs_size > max_index) { linker_error(prog, "attempt to use %d vertex attribute slots only %d available ", @@ -2262,6 +2683,53 @@ assign_attribute_or_color_locations(gl_shader_program *prog, return true; } +/** + * Match explicit locations of outputs to inputs and deactivate the + * unmatch flag if found so we don't optimise them away. + */ +static void +match_explicit_outputs_to_inputs(struct gl_shader_program *prog, + gl_shader *producer, + gl_shader *consumer) +{ + glsl_symbol_table parameters; + ir_variable *explicit_locations[MAX_VARYING] = { NULL }; + + /* Find all shader outputs in the "producer" stage. + */ + foreach_in_list(ir_instruction, node, producer->ir) { + ir_variable *const var = node->as_variable(); + + if ((var == NULL) || (var->data.mode != ir_var_shader_out)) + continue; + + if (var->data.explicit_location && + var->data.location >= VARYING_SLOT_VAR0) { + const unsigned idx = var->data.location - VARYING_SLOT_VAR0; + if (explicit_locations[idx] == NULL) + explicit_locations[idx] = var; + } + } + + /* Match inputs to outputs */ + foreach_in_list(ir_instruction, node, consumer->ir) { + ir_variable *const input = node->as_variable(); + + if ((input == NULL) || (input->data.mode != ir_var_shader_in)) + continue; + + ir_variable *output = NULL; + if (input->data.explicit_location + && input->data.location >= VARYING_SLOT_VAR0) { + output = explicit_locations[input->data.location - VARYING_SLOT_VAR0]; + + if (output != NULL){ + input->data.is_unmatched_generic_inout = 0; + output->data.is_unmatched_generic_inout = 0; + } + } + } +} /** * Demote shader inputs and outputs that are not used in other stages @@ -2386,25 +2854,44 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog) unsigned blocks[MESA_SHADER_STAGES] = {0}; unsigned total_uniform_blocks = 0; + unsigned shader_blocks[MESA_SHADER_STAGES] = {0}; + unsigned total_shader_storage_blocks = 0; - for (unsigned i = 0; i < prog->NumUniformBlocks; i++) { - if (prog->UniformBlocks[i].UniformBufferSize > ctx->Const.MaxUniformBlockSize) { + for (unsigned i = 0; i < prog->NumBufferInterfaceBlocks; i++) { + /* Don't check SSBOs for Uniform Block Size */ + if (!prog->BufferInterfaceBlocks[i].IsShaderStorage && + prog->BufferInterfaceBlocks[i].UniformBufferSize > ctx->Const.MaxUniformBlockSize) { linker_error(prog, "Uniform block %s too big (%d/%d)\n", - prog->UniformBlocks[i].Name, - prog->UniformBlocks[i].UniformBufferSize, + prog->BufferInterfaceBlocks[i].Name, + prog->BufferInterfaceBlocks[i].UniformBufferSize, ctx->Const.MaxUniformBlockSize); } + if (prog->BufferInterfaceBlocks[i].IsShaderStorage && + prog->BufferInterfaceBlocks[i].UniformBufferSize > ctx->Const.MaxShaderStorageBlockSize) { + linker_error(prog, "Shader storage block %s too big (%d/%d)\n", + prog->BufferInterfaceBlocks[i].Name, + prog->BufferInterfaceBlocks[i].UniformBufferSize, + ctx->Const.MaxShaderStorageBlockSize); + } + for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) { - if (prog->UniformBlockStageIndex[j][i] != -1) { - blocks[j]++; - total_uniform_blocks++; + if (prog->InterfaceBlockStageIndex[j][i] != -1) { + struct gl_shader *sh = prog->_LinkedShaders[j]; + int stage_index = prog->InterfaceBlockStageIndex[j][i]; + if (sh && sh->BufferInterfaceBlocks[stage_index].IsShaderStorage) { + shader_blocks[j]++; + total_shader_storage_blocks++; + } else { + blocks[j]++; + total_uniform_blocks++; + } } } if (total_uniform_blocks > ctx->Const.MaxCombinedUniformBlocks) { linker_error(prog, "Too many combined uniform blocks (%d/%d)\n", - prog->NumUniformBlocks, + total_uniform_blocks, ctx->Const.MaxCombinedUniformBlocks); } else { for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { @@ -2419,9 +2906,70 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog) } } } + + if (total_shader_storage_blocks > ctx->Const.MaxCombinedShaderStorageBlocks) { + linker_error(prog, "Too many combined shader storage blocks (%d/%d)\n", + total_shader_storage_blocks, + ctx->Const.MaxCombinedShaderStorageBlocks); + } else { + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + const unsigned max_shader_storage_blocks = + ctx->Const.Program[i].MaxShaderStorageBlocks; + if (shader_blocks[i] > max_shader_storage_blocks) { + linker_error(prog, "Too many %s shader storage blocks (%d/%d)\n", + _mesa_shader_stage_to_string(i), + shader_blocks[i], + max_shader_storage_blocks); + break; + } + } + } } } +static void +link_calculate_subroutine_compat(struct gl_shader_program *prog) +{ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + int count; + if (!sh) + continue; + + for (unsigned j = 0; j < sh->NumSubroutineUniformRemapTable; j++) { + struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[j]; + + if (!uni) + continue; + + count = 0; + for (unsigned f = 0; f < sh->NumSubroutineFunctions; f++) { + struct gl_subroutine_function *fn = &sh->SubroutineFunctions[f]; + for (int k = 0; k < fn->num_compat_types; k++) { + if (fn->types[k] == uni->type) { + count++; + break; + } + } + } + uni->num_compatible_subroutines = count; + } + } +} + +static void +check_subroutine_resources(struct gl_shader_program *prog) +{ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + + if (sh) { + if (sh->NumSubroutineUniformRemapTable > MAX_SUBROUTINE_UNIFORM_LOCATIONS) + linker_error(prog, "Too many %s shader subroutine uniforms\n", + _mesa_shader_stage_to_string(i)); + } + } +} /** * Validate shader image resources. */ @@ -2430,6 +2978,7 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog) { unsigned total_image_units = 0; unsigned fragment_outputs = 0; + unsigned total_shader_storage_blocks = 0; if (!ctx->Extensions.ARB_shader_image_load_store) return; @@ -2439,11 +2988,18 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog) if (sh) { if (sh->NumImages > ctx->Const.Program[i].MaxImageUniforms) - linker_error(prog, "Too many %s shader image uniforms\n", - _mesa_shader_stage_to_string(i)); + linker_error(prog, "Too many %s shader image uniforms (%u > %u)\n", + _mesa_shader_stage_to_string(i), sh->NumImages, + ctx->Const.Program[i].MaxImageUniforms); total_image_units += sh->NumImages; + for (unsigned j = 0; j < prog->NumBufferInterfaceBlocks; j++) { + int stage_index = prog->InterfaceBlockStageIndex[i][j]; + if (stage_index != -1 && sh->BufferInterfaceBlocks[stage_index].IsShaderStorage) + total_shader_storage_blocks++; + } + if (i == MESA_SHADER_FRAGMENT) { foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *var = node->as_variable(); @@ -2457,9 +3013,10 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog) if (total_image_units > ctx->Const.MaxCombinedImageUniforms) linker_error(prog, "Too many combined image uniforms\n"); - if (total_image_units + fragment_outputs > - ctx->Const.MaxCombinedImageUnitsAndFragmentOutputs) - linker_error(prog, "Too many combined image uniforms and fragment outputs\n"); + if (total_image_units + fragment_outputs + total_shader_storage_blocks > + ctx->Const.MaxCombinedShaderOutputResources) + linker_error(prog, "Too many combined image uniforms, shader storage " + " buffers and fragment outputs\n"); } @@ -2530,6 +3087,59 @@ reserve_explicit_locations(struct gl_shader_program *prog, return true; } +static bool +reserve_subroutine_explicit_locations(struct gl_shader_program *prog, + struct gl_shader *sh, + ir_variable *var) +{ + unsigned slots = var->type->uniform_locations(); + unsigned max_loc = var->data.location + slots - 1; + + /* Resize remap table if locations do not fit in the current one. */ + if (max_loc + 1 > sh->NumSubroutineUniformRemapTable) { + sh->SubroutineUniformRemapTable = + reralloc(sh, sh->SubroutineUniformRemapTable, + gl_uniform_storage *, + max_loc + 1); + + if (!sh->SubroutineUniformRemapTable) { + linker_error(prog, "Out of memory during linking.\n"); + return false; + } + + /* Initialize allocated space. */ + for (unsigned i = sh->NumSubroutineUniformRemapTable; i < max_loc + 1; i++) + sh->SubroutineUniformRemapTable[i] = NULL; + + sh->NumSubroutineUniformRemapTable = max_loc + 1; + } + + for (unsigned i = 0; i < slots; i++) { + unsigned loc = var->data.location + i; + + /* Check if location is already used. */ + if (sh->SubroutineUniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { + + /* ARB_explicit_uniform_location specification states: + * "No two subroutine uniform variables can have the same location + * in the same shader stage, otherwise a compiler or linker error + * will be generated." + */ + linker_error(prog, + "location qualifier for uniform %s overlaps " + "previously used location\n", + var->name); + return false; + } + + /* Initialize location as inactive before optimization + * rounds and location assignment. + */ + sh->SubroutineUniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + } + + return true; +} /** * Check and reserve all explicit uniform locations, called before * any optimizations happen to handle also inactive uniforms and @@ -2560,9 +3170,14 @@ check_explicit_uniform_locations(struct gl_context *ctx, foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *var = node->as_variable(); - if ((var && var->data.mode == ir_var_uniform) && - var->data.explicit_location) { - if (!reserve_explicit_locations(prog, uniform_map, var)) { + if (var && (var->data.mode == ir_var_uniform && + var->data.explicit_location)) { + bool ret; + if (var->type->is_subroutine()) + ret = reserve_subroutine_explicit_locations(prog, sh, var); + else + ret = reserve_explicit_locations(prog, uniform_map, var); + if (!ret) { delete uniform_map; return; } @@ -2573,6 +3188,81 @@ check_explicit_uniform_locations(struct gl_context *ctx, delete uniform_map; } +static bool +should_add_buffer_variable(struct gl_shader_program *shProg, + GLenum type, const char *name) +{ + bool found_interface = false; + unsigned block_name_len = 0; + const char *block_name_dot = strchr(name, '.'); + + /* These rules only apply to buffer variables. So we return + * true for the rest of types. + */ + if (type != GL_BUFFER_VARIABLE) + return true; + + for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) { + const char *block_name = shProg->BufferInterfaceBlocks[i].Name; + block_name_len = strlen(block_name); + + const char *block_square_bracket = strchr(block_name, '['); + if (block_square_bracket) { + /* The block is part of an array of named interfaces, + * for the name comparison we ignore the "[x]" part. + */ + block_name_len -= strlen(block_square_bracket); + } + + if (block_name_dot) { + /* Check if the variable name starts with the interface + * name. The interface name (if present) should have the + * length than the interface block name we are comparing to. + */ + unsigned len = strlen(name) - strlen(block_name_dot); + if (len != block_name_len) + continue; + } + + if (strncmp(block_name, name, block_name_len) == 0) { + found_interface = true; + break; + } + } + + /* We remove the interface name from the buffer variable name, + * including the dot that follows it. + */ + if (found_interface) + name = name + block_name_len + 1; + + /* From: ARB_program_interface_query extension: + * + * "For an active shader storage block member declared as an array, an + * entry will be generated only for the first array element, regardless + * of its type. For arrays of aggregate types, the enumeration rules are + * applied recursively for the single enumerated array element. + */ + const char *struct_first_dot = strchr(name, '.'); + const char *first_square_bracket = strchr(name, '['); + + /* The buffer variable is on top level and it is not an array */ + if (!first_square_bracket) { + return true; + /* The shader storage block member is a struct, then generate the entry */ + } else if (struct_first_dot && struct_first_dot < first_square_bracket) { + return true; + } else { + /* Shader storage block member is an array, only generate an entry for the + * first array element. + */ + if (strncmp(first_square_bracket, "[0]", 3) == 0) + return true; + } + + return false; +} + static bool add_program_resource(struct gl_shader_program *prog, GLenum type, const void *data, uint8_t stages) @@ -2607,11 +3297,41 @@ add_program_resource(struct gl_shader_program *prog, GLenum type, return true; } +/* Function checks if a variable var is a packed varying and + * if given name is part of packed varying's list. + * + * If a variable is a packed varying, it has a name like + * 'packed:a,b,c' where a, b and c are separate variables. + */ +static bool +included_in_packed_varying(ir_variable *var, const char *name) +{ + if (strncmp(var->name, "packed:", 7) != 0) + return false; + + char *list = strdup(var->name + 7); + assert(list); + + bool found = false; + char *saveptr; + char *token = strtok_r(list, ",", &saveptr); + while (token) { + if (strcmp(token, name) == 0) { + found = true; + break; + } + token = strtok_r(NULL, ",", &saveptr); + } + free(list); + return found; +} + /** * Function builds a stage reference bitmask from variable name. */ static uint8_t -build_stageref(struct gl_shader_program *shProg, const char *name) +build_stageref(struct gl_shader_program *shProg, const char *name, + unsigned mode) { uint8_t stages = 0; @@ -2630,9 +3350,31 @@ build_stageref(struct gl_shader_program *shProg, const char *name) */ foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *var = node->as_variable(); - if (var && strcmp(var->name, name) == 0) { - stages |= (1 << i); - break; + if (var) { + unsigned baselen = strlen(var->name); + + if (included_in_packed_varying(var, name)) { + stages |= (1 << i); + break; + } + + /* Type needs to match if specified, otherwise we might + * pick a variable with same name but different interface. + */ + if (var->data.mode != mode) + continue; + + if (strncmp(var->name, name, baselen) == 0) { + /* Check for exact name matches but also check for arrays and + * structs. + */ + if (name[baselen] == '\0' || + name[baselen] == '[' || + name[baselen] == '.') { + stages |= (1 << i); + break; + } + } } } } @@ -2641,9 +3383,9 @@ build_stageref(struct gl_shader_program *shProg, const char *name) static bool add_interface_variables(struct gl_shader_program *shProg, - struct gl_shader *sh, GLenum programInterface) + exec_list *ir, GLenum programInterface) { - foreach_in_list(ir_instruction, node, sh->ir) { + foreach_in_list(ir_instruction, node, ir) { ir_variable *var = node->as_variable(); uint8_t mask = 0; @@ -2678,20 +3420,290 @@ add_interface_variables(struct gl_shader_program *shProg, continue; }; + /* Skip packed varyings, packed varyings are handled separately + * by add_packed_varyings. + */ + if (strncmp(var->name, "packed:", 7) == 0) + continue; + + /* Skip fragdata arrays, these are handled separately + * by add_fragdata_arrays. + */ + if (strncmp(var->name, "gl_out_FragData", 15) == 0) + continue; + if (!add_program_resource(shProg, programInterface, var, - build_stageref(shProg, var->name) | mask)) + build_stageref(shProg, var->name, + var->data.mode) | mask)) return false; } return true; } +static bool +add_packed_varyings(struct gl_shader_program *shProg, int stage) +{ + struct gl_shader *sh = shProg->_LinkedShaders[stage]; + GLenum iface; + + if (!sh || !sh->packed_varyings) + return true; + + foreach_in_list(ir_instruction, node, sh->packed_varyings) { + ir_variable *var = node->as_variable(); + if (var) { + switch (var->data.mode) { + case ir_var_shader_in: + iface = GL_PROGRAM_INPUT; + break; + case ir_var_shader_out: + iface = GL_PROGRAM_OUTPUT; + break; + default: + unreachable("unexpected type"); + } + if (!add_program_resource(shProg, iface, var, + build_stageref(shProg, var->name, + var->data.mode))) + return false; + } + } + return true; +} + +static bool +add_fragdata_arrays(struct gl_shader_program *shProg) +{ + struct gl_shader *sh = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]; + + if (!sh || !sh->fragdata_arrays) + return true; + + foreach_in_list(ir_instruction, node, sh->fragdata_arrays) { + ir_variable *var = node->as_variable(); + if (var) { + assert(var->data.mode == ir_var_shader_out); + if (!add_program_resource(shProg, GL_PROGRAM_OUTPUT, var, + 1 << MESA_SHADER_FRAGMENT)) + return false; + } + } + return true; +} + +static char* +get_top_level_name(const char *name) +{ + const char *first_dot = strchr(name, '.'); + const char *first_square_bracket = strchr(name, '['); + int name_size = 0; + /* From ARB_program_interface_query spec: + * + * "For the property TOP_LEVEL_ARRAY_SIZE, a single integer identifying the + * number of active array elements of the top-level shader storage block + * member containing to the active variable is written to . If the + * top-level block member is not declared as an array, the value one is + * written to . If the top-level block member is an array with no + * declared size, the value zero is written to . + */ + + /* The buffer variable is on top level.*/ + if (!first_square_bracket && !first_dot) + name_size = strlen(name); + else if ((!first_square_bracket || + (first_dot && first_dot < first_square_bracket))) + name_size = first_dot - name; + else + name_size = first_square_bracket - name; + + return strndup(name, name_size); +} + +static char* +get_var_name(const char *name) +{ + const char *first_dot = strchr(name, '.'); + + if (!first_dot) + return strdup(name); + + return strndup(first_dot+1, strlen(first_dot) - 1); +} + +static bool +is_top_level_shader_storage_block_member(const char* name, + const char* interface_name, + const char* field_name) +{ + bool result = false; + + /* If the given variable is already a top-level shader storage + * block member, then return array_size = 1. + * We could have two possibilities: if we have an instanced + * shader storage block or not instanced. + * + * For the first, we check create a name as it was in top level and + * compare it with the real name. If they are the same, then + * the variable is already at top-level. + * + * Full instanced name is: interface name + '.' + var name + + * NULL character + */ + int name_length = strlen(interface_name) + 1 + strlen(field_name) + 1; + char *full_instanced_name = (char *) calloc(name_length, sizeof(char)); + if (!full_instanced_name) { + fprintf(stderr, "%s: Cannot allocate space for name\n", __func__); + return false; + } + + snprintf(full_instanced_name, name_length, "%s.%s", + interface_name, field_name); + + /* Check if its top-level shader storage block member of an + * instanced interface block, or of a unnamed interface block. + */ + if (strcmp(name, full_instanced_name) == 0 || + strcmp(name, field_name) == 0) + result = true; + + free(full_instanced_name); + return result; +} + +static int +get_array_size(struct gl_uniform_storage *uni, const glsl_struct_field *field, + char *interface_name, char *var_name) +{ + /* From GL_ARB_program_interface_query spec: + * + * "For the property TOP_LEVEL_ARRAY_SIZE, a single integer + * identifying the number of active array elements of the top-level + * shader storage block member containing to the active variable is + * written to . If the top-level block member is not + * declared as an array, the value one is written to . If + * the top-level block member is an array with no declared size, + * the value zero is written to . + */ + if (is_top_level_shader_storage_block_member(uni->name, + interface_name, + var_name)) + return 1; + else if (field->type->is_unsized_array()) + return 0; + else if (field->type->is_array()) + return field->type->length; + + return 1; +} + +static int +get_array_stride(struct gl_uniform_storage *uni, const glsl_type *interface, + const glsl_struct_field *field, char *interface_name, + char *var_name) +{ + /* From GL_ARB_program_interface_query: + * + * "For the property TOP_LEVEL_ARRAY_STRIDE, a single integer + * identifying the stride between array elements of the top-level + * shader storage block member containing the active variable is + * written to . For top-level block members declared as + * arrays, the value written is the difference, in basic machine + * units, between the offsets of the active variable for + * consecutive elements in the top-level array. For top-level + * block members not declared as an array, zero is written to + * ." + */ + if (field->type->is_array()) { + const enum glsl_matrix_layout matrix_layout = + glsl_matrix_layout(field->matrix_layout); + bool row_major = matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR; + const glsl_type *array_type = field->type->fields.array; + + if (is_top_level_shader_storage_block_member(uni->name, + interface_name, + var_name)) + return 0; + + if (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) { + if (array_type->is_record() || array_type->is_array()) + return glsl_align(array_type->std140_size(row_major), 16); + else + return MAX2(array_type->std140_base_alignment(row_major), 16); + } else { + return array_type->std430_array_stride(row_major); + } + } + return 0; +} + +static void +calculate_array_size_and_stride(struct gl_shader_program *shProg, + struct gl_uniform_storage *uni) +{ + int block_index = uni->block_index; + int array_size = -1; + int array_stride = -1; + char *var_name = get_top_level_name(uni->name); + char *interface_name = + get_top_level_name(shProg->BufferInterfaceBlocks[block_index].Name); + + if (strcmp(var_name, interface_name) == 0) { + /* Deal with instanced array of SSBOs */ + char *temp_name = get_var_name(uni->name); + if (!temp_name) { + linker_error(shProg, "Out of memory during linking.\n"); + goto write_top_level_array_size_and_stride; + } + free(var_name); + var_name = get_top_level_name(temp_name); + free(temp_name); + if (!var_name) { + linker_error(shProg, "Out of memory during linking.\n"); + goto write_top_level_array_size_and_stride; + } + } + + for (unsigned i = 0; i < shProg->NumShaders; i++) { + if (shProg->Shaders[i] == NULL) + continue; + + const gl_shader *stage = shProg->Shaders[i]; + foreach_in_list(ir_instruction, node, stage->ir) { + ir_variable *var = node->as_variable(); + if (!var || !var->get_interface_type() || + var->data.mode != ir_var_shader_storage) + continue; + + const glsl_type *interface = var->get_interface_type(); + + if (strcmp(interface_name, interface->name) != 0) + continue; + + for (unsigned i = 0; i < interface->length; i++) { + const glsl_struct_field *field = &interface->fields.structure[i]; + if (strcmp(field->name, var_name) != 0) + continue; + + array_stride = get_array_stride(uni, interface, field, + interface_name, var_name); + array_size = get_array_size(uni, field, interface_name, var_name); + goto write_top_level_array_size_and_stride; + } + } + } +write_top_level_array_size_and_stride: + free(interface_name); + free(var_name); + uni->top_level_array_stride = array_stride; + uni->top_level_array_size = array_size; +} + /** * Builds up a list of program resources that point to existing * resource data. */ -static void -build_program_resource_list(struct gl_context *ctx, - struct gl_shader_program *shProg) +void +build_program_resource_list(struct gl_shader_program *shProg) { /* Rebuild resource list. */ if (shProg->ProgramResourceList) { @@ -2718,24 +3730,32 @@ build_program_resource_list(struct gl_context *ctx, if (input_stage == MESA_SHADER_STAGES && output_stage == 0) return; + /* Program interface needs to expose varyings in case of SSO. */ + if (shProg->SeparateShader) { + if (!add_packed_varyings(shProg, input_stage)) + return; + if (!add_packed_varyings(shProg, output_stage)) + return; + } + + if (!add_fragdata_arrays(shProg)) + return; + /* Add inputs and outputs to the resource list. */ - if (!add_interface_variables(shProg, shProg->_LinkedShaders[input_stage], + if (!add_interface_variables(shProg, shProg->_LinkedShaders[input_stage]->ir, GL_PROGRAM_INPUT)) return; - if (!add_interface_variables(shProg, shProg->_LinkedShaders[output_stage], + if (!add_interface_variables(shProg, shProg->_LinkedShaders[output_stage]->ir, GL_PROGRAM_OUTPUT)) return; /* Add transform feedback varyings. */ if (shProg->LinkedTransformFeedback.NumVarying > 0) { for (int i = 0; i < shProg->LinkedTransformFeedback.NumVarying; i++) { - uint8_t stageref = - build_stageref(shProg, - shProg->LinkedTransformFeedback.Varyings[i].Name); if (!add_program_resource(shProg, GL_TRANSFORM_FEEDBACK_VARYING, &shProg->LinkedTransformFeedback.Varyings[i], - stageref)) + 0)) return; } } @@ -2747,26 +3767,39 @@ build_program_resource_list(struct gl_context *ctx, continue; uint8_t stageref = - build_stageref(shProg, shProg->UniformStorage[i].name); + build_stageref(shProg, shProg->UniformStorage[i].name, + ir_var_uniform); /* Add stagereferences for uniforms in a uniform block. */ int block_index = shProg->UniformStorage[i].block_index; if (block_index != -1) { for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) { - if (shProg->UniformBlockStageIndex[j][block_index] != -1) + if (shProg->InterfaceBlockStageIndex[j][block_index] != -1) stageref |= (1 << j); } } - if (!add_program_resource(shProg, GL_UNIFORM, + bool is_shader_storage = shProg->UniformStorage[i].is_shader_storage; + GLenum type = is_shader_storage ? GL_BUFFER_VARIABLE : GL_UNIFORM; + if (!should_add_buffer_variable(shProg, type, + shProg->UniformStorage[i].name)) + continue; + + if (is_shader_storage) { + calculate_array_size_and_stride(shProg, &shProg->UniformStorage[i]); + } + + if (!add_program_resource(shProg, type, &shProg->UniformStorage[i], stageref)) return; } - /* Add program uniform blocks. */ - for (unsigned i = 0; i < shProg->NumUniformBlocks; i++) { - if (!add_program_resource(shProg, GL_UNIFORM_BLOCK, - &shProg->UniformBlocks[i], 0)) + /* Add program uniform blocks and shader storage blocks. */ + for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) { + bool is_shader_storage = shProg->BufferInterfaceBlocks[i].IsShaderStorage; + GLenum type = is_shader_storage ? GL_SHADER_STORAGE_BLOCK : GL_UNIFORM_BLOCK; + if (!add_program_resource(shProg, type, + &shProg->BufferInterfaceBlocks[i], 0)) return; } @@ -2777,11 +3810,36 @@ build_program_resource_list(struct gl_context *ctx, return; } - /* TODO - following extensions will require more resource types: - * - * GL_ARB_shader_storage_buffer_object - * GL_ARB_shader_subroutine - */ + for (unsigned i = 0; i < shProg->NumUniformStorage; i++) { + GLenum type; + if (!shProg->UniformStorage[i].hidden) + continue; + + for (int j = MESA_SHADER_VERTEX; j < MESA_SHADER_STAGES; j++) { + if (!shProg->UniformStorage[i].opaque[j].active || + !shProg->UniformStorage[i].type->is_subroutine()) + continue; + + type = _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j); + /* add shader subroutines */ + if (!add_program_resource(shProg, type, &shProg->UniformStorage[i], 0)) + return; + } + } + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_shader *sh = shProg->_LinkedShaders[i]; + GLuint type; + + if (!sh) + continue; + + type = _mesa_shader_stage_to_subroutine((gl_shader_stage)i); + for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) { + if (!add_program_resource(shProg, type, &sh->SubroutineFunctions[j], 0)) + return; + } + } } /** @@ -2818,6 +3876,180 @@ validate_sampler_array_indexing(struct gl_context *ctx, return true; } +static void +link_assign_subroutine_types(struct gl_shader_program *prog) +{ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + gl_shader *sh = prog->_LinkedShaders[i]; + + if (sh == NULL) + continue; + + foreach_in_list(ir_instruction, node, sh->ir) { + ir_function *fn = node->as_function(); + if (!fn) + continue; + + if (fn->is_subroutine) + sh->NumSubroutineUniformTypes++; + + if (!fn->num_subroutine_types) + continue; + + sh->SubroutineFunctions = reralloc(sh, sh->SubroutineFunctions, + struct gl_subroutine_function, + sh->NumSubroutineFunctions + 1); + sh->SubroutineFunctions[sh->NumSubroutineFunctions].name = ralloc_strdup(sh, fn->name); + sh->SubroutineFunctions[sh->NumSubroutineFunctions].num_compat_types = fn->num_subroutine_types; + sh->SubroutineFunctions[sh->NumSubroutineFunctions].types = + ralloc_array(sh, const struct glsl_type *, + fn->num_subroutine_types); + + /* From Section 4.4.4(Subroutine Function Layout Qualifiers) of the + * GLSL 4.5 spec: + * + * "Each subroutine with an index qualifier in the shader must be + * given a unique index, otherwise a compile or link error will be + * generated." + */ + for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) { + if (sh->SubroutineFunctions[j].index != -1 && + sh->SubroutineFunctions[j].index == fn->subroutine_index) { + linker_error(prog, "each subroutine index qualifier in the " + "shader must be unique\n"); + return; + } + } + sh->SubroutineFunctions[sh->NumSubroutineFunctions].index = + fn->subroutine_index; + + for (int j = 0; j < fn->num_subroutine_types; j++) + sh->SubroutineFunctions[sh->NumSubroutineFunctions].types[j] = fn->subroutine_types[j]; + sh->NumSubroutineFunctions++; + } + + /* Assign index for subroutines without an explicit index*/ + int index = 0; + for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) { + while (sh->SubroutineFunctions[j].index == -1) { + for (unsigned k = 0; k < sh->NumSubroutineFunctions; k++) { + if (sh->SubroutineFunctions[k].index == index) + break; + else if (k == sh->NumSubroutineFunctions - 1) + sh->SubroutineFunctions[j].index = index; + } + index++; + } + } + } +} + +static void +split_ubos_and_ssbos(void *mem_ctx, + struct gl_uniform_block *blocks, + unsigned num_blocks, + struct gl_uniform_block ***ubos, + unsigned *num_ubos, + struct gl_uniform_block ***ssbos, + unsigned *num_ssbos) +{ + unsigned num_ubo_blocks = 0; + unsigned num_ssbo_blocks = 0; + + for (unsigned i = 0; i < num_blocks; i++) { + if (blocks[i].IsShaderStorage) + num_ssbo_blocks++; + else + num_ubo_blocks++; + } + + *ubos = ralloc_array(mem_ctx, gl_uniform_block *, num_ubo_blocks); + *num_ubos = 0; + + *ssbos = ralloc_array(mem_ctx, gl_uniform_block *, num_ssbo_blocks); + *num_ssbos = 0; + + for (unsigned i = 0; i < num_blocks; i++) { + if (blocks[i].IsShaderStorage) { + (*ssbos)[(*num_ssbos)++] = &blocks[i]; + } else { + (*ubos)[(*num_ubos)++] = &blocks[i]; + } + } + + assert(*num_ubos + *num_ssbos == num_blocks); +} + +static void +set_always_active_io(exec_list *ir, ir_variable_mode io_mode) +{ + assert(io_mode == ir_var_shader_in || io_mode == ir_var_shader_out); + + foreach_in_list(ir_instruction, node, ir) { + ir_variable *const var = node->as_variable(); + + if (var == NULL || var->data.mode != io_mode) + continue; + + /* Don't set always active on builtins that haven't been redeclared */ + if (var->data.how_declared == ir_var_declared_implicitly) + continue; + + var->data.always_active_io = true; + } +} + +/** + * When separate shader programs are enabled, only input/outputs between + * the stages of a multi-stage separate program can be safely removed + * from the shader interface. Other inputs/outputs must remain active. + */ +static void +disable_varying_optimizations_for_sso(struct gl_shader_program *prog) +{ + unsigned first, last; + assert(prog->SeparateShader); + + first = MESA_SHADER_STAGES; + last = 0; + + /* Determine first and last stage. Excluding the compute stage */ + for (unsigned i = 0; i < MESA_SHADER_COMPUTE; i++) { + if (!prog->_LinkedShaders[i]) + continue; + if (first == MESA_SHADER_STAGES) + first = i; + last = i; + } + + if (first == MESA_SHADER_STAGES) + return; + + for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { + gl_shader *sh = prog->_LinkedShaders[stage]; + if (!sh) + continue; + + if (first == last) { + /* For a single shader program only allow inputs to the vertex shader + * and outputs from the fragment shader to be removed. + */ + if (stage != MESA_SHADER_VERTEX) + set_always_active_io(sh->ir, ir_var_shader_in); + if (stage != MESA_SHADER_FRAGMENT) + set_always_active_io(sh->ir, ir_var_shader_out); + } else { + /* For multi-stage separate shader programs only allow inputs and + * outputs between the shader stages to be removed as well as inputs + * to the vertex shader and outputs from the fragment shader. + */ + if (stage == first && stage != MESA_SHADER_VERTEX) + set_always_active_io(sh->ir, ir_var_shader_in); + else if (stage == last && stage != MESA_SHADER_FRAGMENT) + set_always_active_io(sh->ir, ir_var_shader_out); + } + } +} void link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) @@ -2879,7 +4111,26 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) prog->Version = max_version; prog->IsES = is_es_prog; - /* Geometry shaders have to be linked with vertex shaders. + /* From OpenGL 4.5 Core specification (7.3 Program Objects): + * "Linking can fail for a variety of reasons as specified in the OpenGL + * Shading Language Specification, as well as any of the following + * reasons: + * + * * No shader objects are attached to program. + * + * ..." + * + * Same rule applies for OpenGL ES >= 3.1. + */ + + if (prog->NumShaders == 0 && + ((ctx->API == API_OPENGL_CORE && ctx->Version >= 45) || + (ctx->API == API_OPENGLES2 && ctx->Version >= 31))) { + linker_error(prog, "No shader objects are attached to program.\n"); + goto done; + } + + /* Some shaders have to be linked with some other shaders present. */ if (num_shaders[MESA_SHADER_GEOMETRY] > 0 && num_shaders[MESA_SHADER_VERTEX] == 0 && @@ -2888,6 +4139,44 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) "vertex shader\n"); goto done; } + if (num_shaders[MESA_SHADER_TESS_EVAL] > 0 && + num_shaders[MESA_SHADER_VERTEX] == 0 && + !prog->SeparateShader) { + linker_error(prog, "Tessellation evaluation shader must be linked with " + "vertex shader\n"); + goto done; + } + if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && + num_shaders[MESA_SHADER_VERTEX] == 0 && + !prog->SeparateShader) { + linker_error(prog, "Tessellation control shader must be linked with " + "vertex shader\n"); + goto done; + } + + /* The spec is self-contradictory here. It allows linking without a tess + * eval shader, but that can only be used with transform feedback and + * rasterization disabled. However, transform feedback isn't allowed + * with GL_PATCHES, so it can't be used. + * + * More investigation showed that the idea of transform feedback after + * a tess control shader was dropped, because some hw vendors couldn't + * support tessellation without a tess eval shader, but the linker section + * wasn't updated to reflect that. + * + * All specifications (ARB_tessellation_shader, GL 4.0-4.5) have this + * spec bug. + * + * Do what's reasonable and always require a tess eval shader if a tess + * control shader is present. + */ + if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && + num_shaders[MESA_SHADER_TESS_EVAL] == 0 && + !prog->SeparateShader) { + linker_error(prog, "Tessellation control shader must be linked with " + "tessellation evaluation shader\n"); + goto done; + } /* Compute shaders have additional restrictions. */ if (num_shaders[MESA_SHADER_COMPUTE] > 0 && @@ -2898,7 +4187,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) for (unsigned int i = 0; i < MESA_SHADER_STAGES; i++) { if (prog->_LinkedShaders[i] != NULL) - ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]); + _mesa_delete_shader(ctx, prog->_LinkedShaders[i]); prog->_LinkedShaders[i] = NULL; } @@ -2913,7 +4202,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->LinkStatus) { if (sh) - ctx->Driver.DeleteShader(ctx, sh); + _mesa_delete_shader(ctx, sh); goto done; } @@ -2921,6 +4210,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) case MESA_SHADER_VERTEX: validate_vertex_shader_executable(prog, sh); break; + case MESA_SHADER_TESS_CTRL: + /* nothing to be done */ + break; + case MESA_SHADER_TESS_EVAL: + validate_tess_eval_shader_executable(prog, sh); + break; case MESA_SHADER_GEOMETRY: validate_geometry_shader_executable(prog, sh); break; @@ -2930,7 +4225,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } if (!prog->LinkStatus) { if (sh) - ctx->Driver.DeleteShader(ctx, sh); + _mesa_delete_shader(ctx, sh); goto done; } @@ -2940,6 +4235,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (num_shaders[MESA_SHADER_GEOMETRY] > 0) prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize; + else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0) + prog->LastClipDistanceArraySize = prog->TessEval.ClipDistanceArraySize; else if (num_shaders[MESA_SHADER_VERTEX] > 0) prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize; else @@ -2953,20 +4250,32 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->LinkStatus) goto done; - unsigned prev; + unsigned first, last, prev; - for (prev = 0; prev <= MESA_SHADER_FRAGMENT; prev++) { - if (prog->_LinkedShaders[prev] != NULL) - break; + first = MESA_SHADER_STAGES; + last = 0; + + /* Determine first and last stage. */ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (!prog->_LinkedShaders[i]) + continue; + if (first == MESA_SHADER_STAGES) + first = i; + last = i; } check_explicit_uniform_locations(ctx, prog); + link_assign_subroutine_types(prog); + if (!prog->LinkStatus) goto done; + resize_tes_inputs(ctx, prog); + /* Validate the inputs of each stage with the output of the preceding * stage. */ + prev = first; for (unsigned i = prev + 1; i <= MESA_SHADER_FRAGMENT; i++) { if (prog->_LinkedShaders[i] == NULL) continue; @@ -3009,6 +4318,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } + if (prog->SeparateShader) + disable_varying_optimizations_for_sso(prog); + if (!interstage_cross_validate_uniform_blocks(prog)) goto done; @@ -3028,6 +4340,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) lower_clip_distance(prog->_LinkedShaders[i]); } + if (ctx->Const.LowerTessLevel) { + lower_tess_level(prog->_LinkedShaders[i]); + } + while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, &ctx->Const.ShaderCompilerOptions[i], ctx->Const.NativeIntegers)) @@ -3056,31 +4372,24 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } - /* FINISHME: The value of the max_attribute_index parameter is - * FINISHME: implementation dependent based on the value of - * FINISHME: GL_MAX_VERTEX_ATTRIBS. GL_MAX_VERTEX_ATTRIBS must be - * FINISHME: at least 16, so hardcode 16 for now. - */ - if (!assign_attribute_or_color_locations(prog, MESA_SHADER_VERTEX, 16)) { - goto done; + prev = first; + for (unsigned i = prev + 1; i <= MESA_SHADER_FRAGMENT; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + match_explicit_outputs_to_inputs(prog, prog->_LinkedShaders[prev], + prog->_LinkedShaders[i]); + prev = i; } - if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, MAX2(ctx->Const.MaxDrawBuffers, ctx->Const.MaxDualSourceDrawBuffers))) { + if (!assign_attribute_or_color_locations(prog, &ctx->Const, + MESA_SHADER_VERTEX)) { goto done; } - unsigned first, last; - - first = MESA_SHADER_STAGES; - last = 0; - - /* Determine first and last stage. */ - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (!prog->_LinkedShaders[i]) - continue; - if (first == MESA_SHADER_STAGES) - first = i; - last = i; + if (!assign_attribute_or_color_locations(prog, &ctx->Const, + MESA_SHADER_FRAGMENT)) { + goto done; } if (num_tfeedback_decls != 0) { @@ -3124,8 +4433,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) */ if (!assign_varying_locations(ctx, mem_ctx, prog, NULL, prog->_LinkedShaders[first], - num_tfeedback_decls, tfeedback_decls, - prog->Geom.VerticesIn)) + num_tfeedback_decls, tfeedback_decls)) goto done; } @@ -3136,21 +4444,21 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) */ if (!assign_varying_locations(ctx, mem_ctx, prog, sh, NULL, - num_tfeedback_decls, tfeedback_decls, - 0)) + num_tfeedback_decls, tfeedback_decls)) goto done; } do_dead_builtin_varyings(ctx, sh, NULL, num_tfeedback_decls, tfeedback_decls); - if (!prog->SeparateShader) + if (!prog->SeparateShader) { demote_shader_inputs_and_outputs(sh, ir_var_shader_out); - - /* Eliminate code that is now dead due to unused outputs being demoted. - */ - while (do_dead_code(sh->ir, false)) - ; + /* Eliminate code that is now dead due to unused outputs being + * demoted. + */ + while (do_dead_code(sh->ir, false)) + ; + } } else if (first == MESA_SHADER_FRAGMENT) { /* If the program only contains a fragment shader... @@ -3165,14 +4473,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) NULL /* producer */, sh /* consumer */, 0 /* num_tfeedback_decls */, - NULL /* tfeedback_decls */, - 0 /* gs_input_vertices */)) + NULL /* tfeedback_decls */)) goto done; - } else + } else { demote_shader_inputs_and_outputs(sh, ir_var_shader_in); - - while (do_dead_code(sh->ir, false)) - ; + /* Eliminate code that is now dead due to unused inputs being + * demoted. + */ + while (do_dead_code(sh->ir, false)) + ; + } } next = last; @@ -3182,12 +4492,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) gl_shader *const sh_i = prog->_LinkedShaders[i]; gl_shader *const sh_next = prog->_LinkedShaders[next]; - unsigned gs_input_vertices = - next == MESA_SHADER_GEOMETRY ? prog->Geom.VerticesIn : 0; if (!assign_varying_locations(ctx, mem_ctx, prog, sh_i, sh_next, next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0, - tfeedback_decls, gs_input_vertices)) + tfeedback_decls)) goto done; do_dead_builtin_varyings(ctx, sh_i, sh_next, @@ -3221,7 +4529,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) link_assign_atomic_counter_resources(ctx, prog); store_fragdepth_layout(prog); + link_calculate_subroutine_compat(prog); check_resources(ctx, prog); + check_subroutine_resources(prog); check_image_resources(ctx, prog); link_check_atomic_counter_resources(ctx, prog); @@ -3235,19 +4545,71 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) * behavior specified in GLSL specification. */ if (!prog->SeparateShader && ctx->API == API_OPENGLES2) { - if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) { - linker_error(prog, "program lacks a vertex shader\n"); - } else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) { - linker_error(prog, "program lacks a fragment shader\n"); + /* With ES < 3.1 one needs to have always vertex + fragment shader. */ + if (ctx->Version < 31) { + if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) { + linker_error(prog, "program lacks a vertex shader\n"); + } else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) { + linker_error(prog, "program lacks a fragment shader\n"); + } + } else { + /* From OpenGL ES 3.1 specification (7.3 Program Objects): + * "Linking can fail for a variety of reasons as specified in the + * OpenGL ES Shading Language Specification, as well as any of the + * following reasons: + * + * ... + * + * * program contains objects to form either a vertex shader or + * fragment shader, and program is not separable, and does not + * contain objects to form both a vertex shader and fragment + * shader." + */ + if (!!prog->_LinkedShaders[MESA_SHADER_VERTEX] ^ + !!prog->_LinkedShaders[MESA_SHADER_FRAGMENT]) { + linker_error(prog, "Program needs to contain both vertex and " + "fragment shaders.\n"); + } } } - build_program_resource_list(ctx, prog); - if (!prog->LinkStatus) - goto done; + /* Split BufferInterfaceBlocks into UniformBlocks and ShaderStorageBlocks + * for gl_shader_program and gl_shader, so that drivers that need separate + * index spaces for each set can have that. + */ + for (unsigned i = MESA_SHADER_VERTEX; i < MESA_SHADER_STAGES; i++) { + if (prog->_LinkedShaders[i] != NULL) { + gl_shader *sh = prog->_LinkedShaders[i]; + split_ubos_and_ssbos(sh, + sh->BufferInterfaceBlocks, + sh->NumBufferInterfaceBlocks, + &sh->UniformBlocks, + &sh->NumUniformBlocks, + &sh->ShaderStorageBlocks, + &sh->NumShaderStorageBlocks); + } + } + + split_ubos_and_ssbos(prog, + prog->BufferInterfaceBlocks, + prog->NumBufferInterfaceBlocks, + &prog->UniformBlocks, + &prog->NumUniformBlocks, + &prog->ShaderStorageBlocks, + &prog->NumShaderStorageBlocks); /* FINISHME: Assign fragment shader output locations. */ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + if (ctx->Const.ShaderCompilerOptions[i].LowerBufferInterfaceBlocks) + lower_ubo_reference(prog->_LinkedShaders[i]); + + lower_vector_derefs(prog->_LinkedShaders[i]); + } + done: for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { free(shader_list[i]);