+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_pipeline_object *pipe = _mesa_lookup_pipeline_object(ctx, pipeline);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetProgramPipelineiv(%u, %d, %p)\n",
+ pipeline, pname, params);
+
+ /* Are geometry shaders available in this context?
+ */
+ const bool has_gs = _mesa_has_geometry_shaders(ctx);
+ const bool has_tess = _mesa_has_tessellation(ctx);
+
+ if (!pipe) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramPipelineiv(pipeline)");
+ return;
+ }
+
+ /* Object is created by any Pipeline call but glGenProgramPipelines,
+ * glIsProgramPipeline and GetProgramPipelineInfoLog
+ */
+ pipe->EverBound = GL_TRUE;
+
+ switch (pname) {
+ case GL_ACTIVE_PROGRAM:
+ *params = pipe->ActiveProgram ? pipe->ActiveProgram->Name : 0;
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = (pipe->InfoLog && pipe->InfoLog[0] != '\0') ?
+ strlen(pipe->InfoLog) + 1 : 0;
+ return;
+ case GL_VALIDATE_STATUS:
+ *params = pipe->Validated;
+ return;
+ case GL_VERTEX_SHADER:
+ *params = pipe->CurrentProgram[MESA_SHADER_VERTEX]
+ ? pipe->CurrentProgram[MESA_SHADER_VERTEX]->Name : 0;
+ return;
+ case GL_TESS_EVALUATION_SHADER:
+ if (!has_tess)
+ break;
+ *params = pipe->CurrentProgram[MESA_SHADER_TESS_EVAL]
+ ? pipe->CurrentProgram[MESA_SHADER_TESS_EVAL]->Name : 0;
+ return;
+ case GL_TESS_CONTROL_SHADER:
+ if (!has_tess)
+ break;
+ *params = pipe->CurrentProgram[MESA_SHADER_TESS_CTRL]
+ ? pipe->CurrentProgram[MESA_SHADER_TESS_CTRL]->Name : 0;
+ return;
+ case GL_GEOMETRY_SHADER:
+ if (!has_gs)
+ break;
+ *params = pipe->CurrentProgram[MESA_SHADER_GEOMETRY]
+ ? pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Name : 0;
+ return;
+ case GL_FRAGMENT_SHADER:
+ *params = pipe->CurrentProgram[MESA_SHADER_FRAGMENT]
+ ? pipe->CurrentProgram[MESA_SHADER_FRAGMENT]->Name : 0;
+ return;
+ case GL_COMPUTE_SHADER:
+ if (!_mesa_has_compute_shaders(ctx))
+ break;
+ *params = pipe->CurrentProgram[MESA_SHADER_COMPUTE]
+ ? pipe->CurrentProgram[MESA_SHADER_COMPUTE]->Name : 0;
+ return;
+ default:
+ break;
+ }
+
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramPipelineiv(pname=%s)",
+ _mesa_enum_to_string(pname));
+}
+
+/**
+ * Determines whether every stage in a linked program is active in the
+ * specified pipeline.
+ */
+static bool
+program_stages_all_active(struct gl_pipeline_object *pipe,
+ const struct gl_shader_program *prog)
+{
+ unsigned i;
+ bool status = true;
+
+ if (!prog)
+ return true;
+
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (prog->_LinkedShaders[i]) {
+ if (pipe->CurrentProgram[i]) {
+ if (prog->Name != pipe->CurrentProgram[i]->Name) {
+ status = false;
+ }
+ } else {
+ status = false;
+ }
+ }
+ }
+
+ if (!status) {
+ pipe->InfoLog = ralloc_asprintf(pipe,
+ "Program %d is not active for all "
+ "shaders that was linked",
+ prog->Name);
+ }
+
+ return status;
+}
+
+static bool
+program_stages_interleaved_illegally(const struct gl_pipeline_object *pipe)
+{
+ unsigned prev_linked_stages = 0;
+
+ /* Look for programs bound to stages: A -> B -> A, with any intervening
+ * sequence of unrelated programs or empty stages.
+ */
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_shader_program *cur = pipe->CurrentProgram[i];
+
+ /* Empty stages anywhere in the pipe are OK. Also we can be confident
+ * that if the linked_stages mask matches we are looking at the same
+ * linked program because a previous validation call to
+ * program_stages_all_active() will have already failed if two different
+ * programs with the sames stages linked are not active for all linked
+ * stages.
+ */
+ if (!cur || cur->data->linked_stages == prev_linked_stages)
+ continue;
+
+ if (prev_linked_stages) {
+ /* We've seen an A -> B transition; look at the rest of the pipe
+ * to see if we ever see A again.
+ */
+ if (prev_linked_stages >> (i + 1))
+ return true;
+ }
+
+ prev_linked_stages = cur->data->linked_stages;
+ }
+
+ return false;
+}
+
+extern GLboolean
+_mesa_validate_program_pipeline(struct gl_context* ctx,
+ struct gl_pipeline_object *pipe)
+{
+ unsigned i;
+ bool program_empty = true;
+
+ pipe->Validated = GL_FALSE;
+
+ /* Release and reset the info log.
+ */
+ if (pipe->InfoLog != NULL)
+ ralloc_free(pipe->InfoLog);
+
+ pipe->InfoLog = NULL;
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * - A program object is active for at least one, but not all of
+ * the shader stages that were present when the program was
+ * linked."
+ *
+ * For each possible program stage, verify that the program bound to that
+ * stage has all of its stages active. In other words, if the program
+ * bound to the vertex stage also has a fragment shader, the fragment
+ * shader must also be bound to the fragment stage.
+ */
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (!program_stages_all_active(pipe, pipe->CurrentProgram[i])) {
+ return GL_FALSE;
+ }
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - One program object is active for at least two shader stages
+ * and a second program is active for a shader stage between two
+ * stages for which the first program was active."
+ */
+ if (program_stages_interleaved_illegally(pipe)) {
+ pipe->InfoLog =
+ ralloc_strdup(pipe,
+ "Program is active for multiple shader stages with an "
+ "intervening stage provided by another program");
+ return GL_FALSE;
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - There is an active program for tessellation control,
+ * tessellation evaluation, or geometry stages with corresponding
+ * executable shader, but there is no active program with
+ * executable vertex shader."
+ */
+ if (!pipe->CurrentProgram[MESA_SHADER_VERTEX]
+ && (pipe->CurrentProgram[MESA_SHADER_GEOMETRY] ||
+ pipe->CurrentProgram[MESA_SHADER_TESS_CTRL] ||
+ pipe->CurrentProgram[MESA_SHADER_TESS_EVAL])) {
+ pipe->InfoLog = ralloc_strdup(pipe, "Program lacks a vertex shader");
+ return GL_FALSE;
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - There is no current program object specified by UseProgram,
+ * there is a current program pipeline object, and the current
+ * program for any shader stage has been relinked since being
+ * applied to the pipeline object via UseProgramStages with the
+ * PROGRAM_SEPARABLE parameter set to FALSE.
+ */
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (pipe->CurrentProgram[i] && !pipe->CurrentProgram[i]->SeparateShader) {
+ pipe->InfoLog = ralloc_asprintf(pipe,
+ "Program %d was relinked without "
+ "PROGRAM_SEPARABLE state",
+ pipe->CurrentProgram[i]->Name);
+ return GL_FALSE;
+ }
+ }
+
+ /* Section 11.1.3.11 (Validation) of the OpenGL 4.5 spec says:
+ *
+ * "An INVALID_OPERATION error is generated by any command that trans-
+ * fers vertices to the GL or launches compute work if the current set
+ * of active program objects cannot be executed, for reasons including:
+ *
+ * ...
+ *
+ * - There is no current program object specified by UseProgram,
+ * there is a current program pipeline object, and that object is
+ * empty (no executable code is installed for any stage).
+ */
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (pipe->CurrentProgram[i]) {
+ program_empty = false;
+ break;
+ }
+ }
+
+ if (program_empty) {
+ return GL_FALSE;
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - Any two active samplers in the current program object are of
+ * different types, but refer to the same texture image unit.
+ *
+ * - The number of active samplers in the program exceeds the
+ * maximum number of texture image units allowed."
+ */
+ if (!_mesa_sampler_uniforms_pipeline_are_valid(pipe))
+ return GL_FALSE;
+
+ /* Validate inputs against outputs, this cannot be done during linking
+ * since programs have been linked separately from each other.
+ *
+ * Section 11.1.3.11 (Validation) of the OpenGL 4.5 Core Profile spec says:
+ *
+ * "Separable program objects may have validation failures that cannot be
+ * detected without the complete program pipeline. Mismatched interfaces,
+ * improper usage of program objects together, and the same
+ * state-dependent failures can result in validation errors for such
+ * program objects."
+ *
+ * OpenGL ES 3.1 specification has the same text.
+ *
+ * Section 11.1.3.11 (Validation) of the OpenGL ES spec also says:
+ *
+ * An INVALID_OPERATION error is generated by any command that transfers
+ * vertices to the GL or launches compute work if the current set of
+ * active program objects cannot be executed, for reasons including:
+ *
+ * * The current program pipeline object contains a shader interface
+ * that doesn't have an exact match (see section 7.4.1)
+ *
+ * Based on this, only perform the most-strict checking on ES or when the
+ * application has created a debug context.
+ */
+ if ((_mesa_is_gles(ctx) || (ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)) &&
+ !_mesa_validate_pipeline_io(pipe)) {
+ if (_mesa_is_gles(ctx))
+ return GL_FALSE;
+
+ static GLuint msg_id = 0;
+
+ _mesa_gl_debug(ctx, &msg_id,
+ MESA_DEBUG_SOURCE_API,
+ MESA_DEBUG_TYPE_PORTABILITY,
+ MESA_DEBUG_SEVERITY_MEDIUM,
+ "glValidateProgramPipeline: pipeline %u does not meet "
+ "strict OpenGL ES 3.1 requirements and may not be "
+ "portable across desktop hardware\n",
+ pipe->Name);
+ }
+
+ pipe->Validated = GL_TRUE;
+ return GL_TRUE;