+
+/**
+ * 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;
+}
+
+