mesa: add support for memory object creation/import/delete
[mesa.git] / src / mesa / main / pipelineobj.c
index 279ae2078fedc6b166d3be64504dd0eb9d438c34..d7d99ec22d8369c78b0e102eab9ea5434aa16ddd 100644 (file)
@@ -31,6 +31,7 @@
  * GL_ARB_separate_shader_objects extension.
  */
 
+#include <stdbool.h>
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/dispatch.h"
 #include "main/shaderobj.h"
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
+#include "compiler/glsl/glsl_parser_extras.h"
+#include "compiler/glsl/ir_uniform.h"
 #include "program/program.h"
 #include "program/prog_parameter.h"
 #include "util/ralloc.h"
-#include <stdbool.h>
-#include "../glsl/glsl_parser_extras.h"
-#include "../glsl/ir_uniform.h"
 
 /**
  * Delete a pipeline object.
@@ -58,13 +58,12 @@ _mesa_delete_pipeline_object(struct gl_context *ctx,
 {
    unsigned i;
 
-   _mesa_reference_shader_program(ctx, &obj->_CurrentFragmentProgram, NULL);
-
-   for (i = 0; i < MESA_SHADER_STAGES; i++)
-      _mesa_reference_shader_program(ctx, &obj->CurrentProgram[i], NULL);
+   for (i = 0; i < MESA_SHADER_STAGES; i++) {
+      _mesa_reference_program(ctx, &obj->CurrentProgram[i], NULL);
+      _mesa_reference_shader_program(ctx, &obj->ReferencedPrograms[i], NULL);
+   }
 
    _mesa_reference_shader_program(ctx, &obj->ActiveProgram, NULL);
-   mtx_destroy(&obj->Mutex);
    free(obj->Label);
    ralloc_free(obj);
 }
@@ -78,7 +77,6 @@ _mesa_new_pipeline_object(struct gl_context *ctx, GLuint name)
    struct gl_pipeline_object *obj = rzalloc(NULL, struct gl_pipeline_object);
    if (obj) {
       obj->Name = name;
-      mtx_init(&obj->Mutex, mtx_plain);
       obj->RefCount = 1;
       obj->Flags = _mesa_get_shader_flags();
       obj->InfoLog = NULL;
@@ -107,7 +105,7 @@ _mesa_init_pipeline(struct gl_context *ctx)
  * Callback for deleting a pipeline object.  Called by _mesa_HashDeleteAll().
  */
 static void
-delete_pipelineobj_cb(GLuint id, void *data, void *userData)
+delete_pipelineobj_cb(UNUSED GLuint id, void *data, void *userData)
 {
    struct gl_pipeline_object *obj = (struct gl_pipeline_object *) data;
    struct gl_context *ctx = (struct gl_context *) userData;
@@ -144,7 +142,7 @@ _mesa_lookup_pipeline_object(struct gl_context *ctx, GLuint id)
       return NULL;
    else
       return (struct gl_pipeline_object *)
-         _mesa_HashLookup(ctx->Pipeline.Objects, id);
+         _mesa_HashLookupLocked(ctx->Pipeline.Objects, id);
 }
 
 /**
@@ -154,7 +152,7 @@ static void
 save_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
 {
    if (obj->Name > 0) {
-      _mesa_HashInsert(ctx->Pipeline.Objects, obj->Name, obj);
+      _mesa_HashInsertLocked(ctx->Pipeline.Objects, obj->Name, obj);
    }
 }
 
@@ -166,7 +164,7 @@ static void
 remove_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
 {
    if (obj->Name > 0) {
-      _mesa_HashRemove(ctx->Pipeline.Objects, obj->Name);
+      _mesa_HashRemoveLocked(ctx->Pipeline.Objects, obj->Name);
    }
 }
 
@@ -184,16 +182,12 @@ _mesa_reference_pipeline_object_(struct gl_context *ctx,
 
    if (*ptr) {
       /* Unreference the old pipeline object */
-      GLboolean deleteFlag = GL_FALSE;
       struct gl_pipeline_object *oldObj = *ptr;
 
-      mtx_lock(&oldObj->Mutex);
       assert(oldObj->RefCount > 0);
       oldObj->RefCount--;
-      deleteFlag = (oldObj->RefCount == 0);
-      mtx_unlock(&oldObj->Mutex);
 
-      if (deleteFlag) {
+      if (oldObj->RefCount == 0) {
          _mesa_delete_pipeline_object(ctx, oldObj);
       }
 
@@ -203,21 +197,84 @@ _mesa_reference_pipeline_object_(struct gl_context *ctx,
 
    if (obj) {
       /* reference new pipeline object */
-      mtx_lock(&obj->Mutex);
-      if (obj->RefCount == 0) {
-         /* this pipeline's being deleted (look just above) */
-         /* Not sure this can ever really happen.  Warn if it does. */
-         _mesa_problem(NULL, "referencing deleted pipeline object");
-         *ptr = NULL;
-      }
-      else {
-         obj->RefCount++;
-         *ptr = obj;
-      }
-      mtx_unlock(&obj->Mutex);
+      assert(obj->RefCount > 0);
+
+      obj->RefCount++;
+      *ptr = obj;
    }
 }
 
+static void
+use_program_stage(struct gl_context *ctx, GLenum type,
+                  struct gl_shader_program *shProg,
+                  struct gl_pipeline_object *pipe) {
+   gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
+   struct gl_program *prog = NULL;
+   if (shProg && shProg->_LinkedShaders[stage])
+      prog = shProg->_LinkedShaders[stage]->Program;
+
+   _mesa_use_program(ctx, stage, shProg, prog, pipe);
+}
+
+static void
+use_program_stages(struct gl_context *ctx, struct gl_shader_program *shProg,
+                   GLbitfield stages, struct gl_pipeline_object *pipe) {
+
+   /* Enable individual stages from the program as requested by the
+    * application.  If there is no shader for a requested stage in the
+    * program, _mesa_use_shader_program will enable fixed-function processing
+    * as dictated by the spec.
+    *
+    * Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec
+    * says:
+    *
+    *     "If UseProgramStages is called with program set to zero or with a
+    *     program object that contains no executable code for the given
+    *     stages, it is as if the pipeline object has no programmable stage
+    *     configured for the indicated shader stages."
+    */
+   if ((stages & GL_VERTEX_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_VERTEX_SHADER, shProg, pipe);
+
+   if ((stages & GL_FRAGMENT_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_FRAGMENT_SHADER, shProg, pipe);
+
+   if ((stages & GL_GEOMETRY_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_GEOMETRY_SHADER, shProg, pipe);
+
+   if ((stages & GL_TESS_CONTROL_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_TESS_CONTROL_SHADER, shProg, pipe);
+
+   if ((stages & GL_TESS_EVALUATION_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_TESS_EVALUATION_SHADER, shProg, pipe);
+
+   if ((stages & GL_COMPUTE_SHADER_BIT) != 0)
+      use_program_stage(ctx, GL_COMPUTE_SHADER, shProg, pipe);
+
+   pipe->Validated = false;
+}
+
+void GLAPIENTRY
+_mesa_UseProgramStages_no_error(GLuint pipeline, GLbitfield stages,
+                                GLuint prog)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_pipeline_object *pipe =
+      _mesa_lookup_pipeline_object(ctx, pipeline);
+   struct gl_shader_program *shProg = NULL;
+
+   if (prog)
+      shProg = _mesa_lookup_shader_program(ctx, prog);
+
+   /* Object is created by any Pipeline call but glGenProgramPipelines,
+    * glIsProgramPipeline and GetProgramPipelineInfoLog
+    */
+   pipe->EverBound = GL_TRUE;
+
+   use_program_stages(ctx, shProg, stages, pipe);
+}
+
 /**
  * Bound program to severals stages of the pipeline
  */
@@ -230,6 +287,10 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
    struct gl_shader_program *shProg = NULL;
    GLbitfield any_valid_stages;
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glUseProgramStages(%u, 0x%x, %u)\n",
+                  pipeline, stages, program);
+
    if (!pipe) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(pipeline)");
       return;
@@ -244,14 +305,15 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
     *
     *     "If stages is not the special value ALL_SHADER_BITS, and has a bit
     *     set that is not recognized, the error INVALID_VALUE is generated."
-    *
-    * NOT YET SUPPORTED:
-    * GL_TESS_CONTROL_SHADER_BIT
-    * GL_TESS_EVALUATION_SHADER_BIT
     */
    any_valid_stages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT;
    if (_mesa_has_geometry_shaders(ctx))
       any_valid_stages |= GL_GEOMETRY_SHADER_BIT;
+   if (_mesa_has_tessellation(ctx))
+      any_valid_stages |= GL_TESS_CONTROL_SHADER_BIT |
+                          GL_TESS_EVALUATION_SHADER_BIT;
+   if (_mesa_has_compute_shaders(ctx))
+      any_valid_stages |= GL_COMPUTE_SHADER_BIT;
 
    if (stages != GL_ALL_SHADER_BITS && (stages & ~any_valid_stages) != 0) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glUseProgramStages(Stages)");
@@ -292,7 +354,7 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
        *     shader stages in the pipeline program pipeline object are not
        *     modified."
        */
-      if (!shProg->LinkStatus) {
+      if (!shProg->data->LinkStatus) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glUseProgramStages(program not linked)");
          return;
@@ -306,48 +368,28 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
       }
    }
 
-   /* Enable individual stages from the program as requested by the
-    * application.  If there is no shader for a requested stage in the
-    * program, _mesa_use_shader_program will enable fixed-function processing
-    * as dictated by the spec.
-    *
-    * Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec
-    * says:
-    *
-    *     "If UseProgramStages is called with program set to zero or with a
-    *     program object that contains no executable code for the given
-    *     stages, it is as if the pipeline object has no programmable stage
-    *     configured for the indicated shader stages."
-    */
-   if ((stages & GL_VERTEX_SHADER_BIT) != 0)
-      _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, shProg, pipe);
-
-   if ((stages & GL_FRAGMENT_SHADER_BIT) != 0)
-      _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, pipe);
-
-   if ((stages & GL_GEOMETRY_SHADER_BIT) != 0)
-      _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER, shProg, pipe);
+   use_program_stages(ctx, shProg, stages, pipe);
 }
 
-/**
- * Use the named shader program for subsequent glUniform calls (if pipeline
- * bound)
- */
-void GLAPIENTRY
-_mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
+static ALWAYS_INLINE void
+active_shader_program(struct gl_context *ctx, GLuint pipeline, GLuint program,
+                      bool no_error)
 {
-   GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg = NULL;
    struct gl_pipeline_object *pipe = _mesa_lookup_pipeline_object(ctx, pipeline);
 
-   if (program != 0) {
-      shProg = _mesa_lookup_shader_program_err(ctx, program,
-                                               "glActiveShaderProgram(program)");
-      if (shProg == NULL)
-         return;
+   if (program) {
+      if (no_error) {
+         shProg = _mesa_lookup_shader_program(ctx, program);
+      } else {
+         shProg = _mesa_lookup_shader_program_err(ctx, program,
+                                                  "glActiveShaderProgram(program)");
+         if (shProg == NULL)
+            return;
+      }
    }
 
-   if (!pipe) {
+   if (!no_error && !pipe) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveShaderProgram(pipeline)");
       return;
    }
@@ -357,7 +399,7 @@ _mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
     */
    pipe->EverBound = GL_TRUE;
 
-   if ((shProg != NULL) && !shProg->LinkStatus) {
+   if (!no_error && shProg != NULL && !shProg->data->LinkStatus) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
             "glActiveShaderProgram(program %u not linked)", shProg->Name);
       return;
@@ -366,15 +408,36 @@ _mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
    _mesa_reference_shader_program(ctx, &pipe->ActiveProgram, shProg);
 }
 
+void GLAPIENTRY
+_mesa_ActiveShaderProgram_no_error(GLuint pipeline, GLuint program)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   active_shader_program(ctx, pipeline, program, true);
+}
+
 /**
- * Make program of the pipeline current
+ * Use the named shader program for subsequent glUniform calls (if pipeline
+ * bound)
  */
 void GLAPIENTRY
-_mesa_BindProgramPipeline(GLuint pipeline)
+_mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
 {
    GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glActiveShaderProgram(%u, %u)\n", pipeline, program);
+
+   active_shader_program(ctx, pipeline, program, false);
+}
+
+static ALWAYS_INLINE void
+bind_program_pipeline(struct gl_context *ctx, GLuint pipeline, bool no_error)
+{
    struct gl_pipeline_object *newObj = NULL;
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glBindProgramPipeline(%u)\n", pipeline);
+
    /* Rebinding the same pipeline object: no change.
     */
    if (ctx->_Shader->Name == pipeline)
@@ -390,7 +453,7 @@ _mesa_BindProgramPipeline(GLuint pipeline)
     *         - by BindProgramPipeline if the current transform feedback
     *           object is active and not paused;
     */
-   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
+   if (!no_error && _mesa_is_xfb_active_and_unpaused(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
             "glBindProgramPipeline(transform feedback active)");
       return;
@@ -401,7 +464,7 @@ _mesa_BindProgramPipeline(GLuint pipeline)
    if (pipeline) {
       /* non-default pipeline object */
       newObj = _mesa_lookup_pipeline_object(ctx, pipeline);
-      if (!newObj) {
+      if (!no_error && !newObj) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBindProgramPipeline(non-gen name)");
          return;
@@ -416,10 +479,28 @@ _mesa_BindProgramPipeline(GLuint pipeline)
    _mesa_bind_pipeline(ctx, newObj);
 }
 
+void GLAPIENTRY
+_mesa_BindProgramPipeline_no_error(GLuint pipeline)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   bind_program_pipeline(ctx, pipeline, true);
+}
+
+/**
+ * Make program of the pipeline current
+ */
+void GLAPIENTRY
+_mesa_BindProgramPipeline(GLuint pipeline)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   bind_program_pipeline(ctx, pipeline, false);
+}
+
 void
 _mesa_bind_pipeline(struct gl_context *ctx,
                     struct gl_pipeline_object *pipe)
 {
+   int i;
    /* First bind the Pipeline to pipeline binding point */
    _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current, pipe);
 
@@ -432,6 +513,8 @@ _mesa_bind_pipeline(struct gl_context *ctx,
     *     considered current."
     */
    if (&ctx->Shader != ctx->_Shader) {
+      FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+
       if (pipe != NULL) {
          /* Bound the pipeline to the current program and
           * restore the pipeline state
@@ -443,10 +526,12 @@ _mesa_bind_pipeline(struct gl_context *ctx,
                                          ctx->Pipeline.Default);
       }
 
-      FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
-
-      if (ctx->Driver.UseProgram)
-         ctx->Driver.UseProgram(ctx, NULL);
+      for (i = 0; i < MESA_SHADER_STAGES; i++) {
+         struct gl_program *prog = ctx->_Shader->CurrentProgram[i];
+         if (prog) {
+            _mesa_program_init_subroutine_defaults(ctx, prog);
+         }
+      }
    }
 }
 
@@ -462,6 +547,9 @@ _mesa_DeleteProgramPipelines(GLsizei n, const GLuint *pipelines)
    GET_CURRENT_CONTEXT(ctx);
    GLsizei i;
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDeleteProgramPipelines(%d, %p)\n", n, pipelines);
+
    if (n < 0) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgramPipelines(n<0)");
       return;
@@ -503,20 +591,12 @@ static void
 create_program_pipelines(struct gl_context *ctx, GLsizei n, GLuint *pipelines,
                          bool dsa)
 {
-   const char *func;
+   const char *func = dsa ? "glCreateProgramPipelines" : "glGenProgramPipelines";
    GLuint first;
    GLint i;
 
-   func = dsa ? "glCreateProgramPipelines" : "glGenProgramPipelines";
-
-   if (n < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s (n < 0)", func);
+   if (!pipelines)
       return;
-   }
-
-   if (!pipelines) {
-      return;
-   }
 
    first = _mesa_HashFindFreeKeyBlock(ctx->Pipeline.Objects, n);
 
@@ -538,7 +618,27 @@ create_program_pipelines(struct gl_context *ctx, GLsizei n, GLuint *pipelines,
       save_pipeline_object(ctx, obj);
       pipelines[i] = first + i;
    }
+}
 
+static void
+create_program_pipelines_err(struct gl_context *ctx, GLsizei n,
+                             GLuint *pipelines, bool dsa)
+{
+   const char *func = dsa ? "glCreateProgramPipelines" : "glGenProgramPipelines";
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s (n < 0)", func);
+      return;
+   }
+
+   create_program_pipelines(ctx, n, pipelines, dsa);
+}
+
+void GLAPIENTRY
+_mesa_GenProgramPipelines_no_error(GLsizei n, GLuint *pipelines)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_program_pipelines(ctx, n, pipelines, false);
 }
 
 void GLAPIENTRY
@@ -546,7 +646,17 @@ _mesa_GenProgramPipelines(GLsizei n, GLuint *pipelines)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   create_program_pipelines(ctx, n, pipelines, false);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glGenProgramPipelines(%d, %p)\n", n, pipelines);
+
+   create_program_pipelines_err(ctx, n, pipelines, false);
+}
+
+void GLAPIENTRY
+_mesa_CreateProgramPipelines_no_error(GLsizei n, GLuint *pipelines)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_program_pipelines(ctx, n, pipelines, true);
 }
 
 void GLAPIENTRY
@@ -554,7 +664,10 @@ _mesa_CreateProgramPipelines(GLsizei n, GLuint *pipelines)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   create_program_pipelines(ctx, n, pipelines, true);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glCreateProgramPipelines(%d, %p)\n", n, pipelines);
+
+   create_program_pipelines_err(ctx, n, pipelines, true);
 }
 
 /**
@@ -569,6 +682,9 @@ _mesa_IsProgramPipeline(GLuint pipeline)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glIsProgramPipeline(%u)\n", pipeline);
+
    struct gl_pipeline_object *obj = _mesa_lookup_pipeline_object(ctx, pipeline);
    if (obj == NULL)
       return GL_FALSE;
@@ -585,9 +701,14 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
    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,
@@ -605,37 +726,50 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
       *params = pipe->ActiveProgram ? pipe->ActiveProgram->Name : 0;
       return;
    case GL_INFO_LOG_LENGTH:
-      *params = pipe->InfoLog ? strlen(pipe->InfoLog) + 1 : 0;
+      *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;
+         ? pipe->CurrentProgram[MESA_SHADER_VERTEX]->Id : 0;
       return;
    case GL_TESS_EVALUATION_SHADER:
-      /* NOT YET SUPPORTED */
-      break;
+      if (!has_tess)
+         break;
+      *params = pipe->CurrentProgram[MESA_SHADER_TESS_EVAL]
+         ? pipe->CurrentProgram[MESA_SHADER_TESS_EVAL]->Id : 0;
+      return;
    case GL_TESS_CONTROL_SHADER:
-      /* NOT YET SUPPORTED */
-      break;
+      if (!has_tess)
+         break;
+      *params = pipe->CurrentProgram[MESA_SHADER_TESS_CTRL]
+         ? pipe->CurrentProgram[MESA_SHADER_TESS_CTRL]->Id : 0;
+      return;
    case GL_GEOMETRY_SHADER:
       if (!has_gs)
          break;
       *params = pipe->CurrentProgram[MESA_SHADER_GEOMETRY]
-         ? pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Name : 0;
+         ? pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Id : 0;
       return;
    case GL_FRAGMENT_SHADER:
       *params = pipe->CurrentProgram[MESA_SHADER_FRAGMENT]
-         ? pipe->CurrentProgram[MESA_SHADER_FRAGMENT]->Name : 0;
+         ? pipe->CurrentProgram[MESA_SHADER_FRAGMENT]->Id : 0;
+      return;
+   case GL_COMPUTE_SHADER:
+      if (!_mesa_has_compute_shaders(ctx))
+         break;
+      *params = pipe->CurrentProgram[MESA_SHADER_COMPUTE]
+         ? pipe->CurrentProgram[MESA_SHADER_COMPUTE]->Id : 0;
       return;
    default:
       break;
    }
 
    _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramPipelineiv(pname=%s)",
-               _mesa_lookup_enum_by_nr(pname));
+               _mesa_enum_to_string(pname));
 }
 
 /**
@@ -644,23 +778,22 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
  */
 static bool
 program_stages_all_active(struct gl_pipeline_object *pipe,
-                          const struct gl_shader_program *prog)
+                          const struct gl_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 {
+   unsigned mask = prog->sh.data->linked_stages;
+   while (mask) {
+      const int i = u_bit_scan(&mask);
+      if (pipe->CurrentProgram[i]) {
+         if (prog->Id != pipe->CurrentProgram[i]->Id) {
             status = false;
          }
+      } else {
+         status = false;
       }
    }
 
@@ -668,7 +801,7 @@ program_stages_all_active(struct gl_pipeline_object *pipe,
       pipe->InfoLog = ralloc_asprintf(pipe,
                                       "Program %d is not active for all "
                                       "shaders that was linked",
-                                      prog->Name);
+                                      prog->Id);
    }
 
    return status;
@@ -677,30 +810,33 @@ program_stages_all_active(struct gl_pipeline_object *pipe,
 static bool
 program_stages_interleaved_illegally(const struct gl_pipeline_object *pipe)
 {
-   struct gl_shader_program *prev = NULL;
-   unsigned i, j;
+   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 (i = 0; i < MESA_SHADER_STAGES; i++) {
-      struct gl_shader_program *cur = pipe->CurrentProgram[i];
-
-      /* Empty stages anywhere in the pipe are OK */
-      if (!cur || cur == prev)
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_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->sh.data->linked_stages == prev_linked_stages)
          continue;
 
-      if (prev) {
+      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.
           */
-         for (j = i + 1; j < MESA_SHADER_STAGES; j++) {
-            if (pipe->CurrentProgram[j] == prev)
-               return true;
-         }
+         if (prev_linked_stages >> (i + 1))
+            return true;
       }
 
-      prev = cur;
+      prev_linked_stages = cur->sh.data->linked_stages;
    }
 
    return false;
@@ -708,10 +844,10 @@ program_stages_interleaved_illegally(const struct gl_pipeline_object *pipe)
 
 extern GLboolean
 _mesa_validate_program_pipeline(struct gl_context* ctx,
-                                struct gl_pipeline_object *pipe,
-                                GLboolean IsBound)
+                                struct gl_pipeline_object *pipe)
 {
    unsigned i;
+   bool program_empty = true;
 
    pipe->Validated = GL_FALSE;
 
@@ -739,7 +875,7 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
     */
    for (i = 0; i < MESA_SHADER_STAGES; i++) {
       if (!program_stages_all_active(pipe, pipe->CurrentProgram[i])) {
-         goto err;
+         return GL_FALSE;
       }
    }
 
@@ -760,7 +896,7 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
          ralloc_strdup(pipe,
                        "Program is active for multiple shader stages with an "
                        "intervening stage provided by another program");
-      goto err;
+      return GL_FALSE;
    }
 
    /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
@@ -777,9 +913,11 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
     *           executable vertex shader."
     */
    if (!pipe->CurrentProgram[MESA_SHADER_VERTEX]
-       && pipe->CurrentProgram[MESA_SHADER_GEOMETRY]) {
+       && (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");
-      goto err;
+      return GL_FALSE;
    }
 
    /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
@@ -797,15 +935,39 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
     *           PROGRAM_SEPARABLE parameter set to FALSE.
     */
    for (i = 0; i < MESA_SHADER_STAGES; i++) {
-      if (pipe->CurrentProgram[i] && !pipe->CurrentProgram[i]->SeparateShader) {
+      if (pipe->CurrentProgram[i] &&
+          !pipe->CurrentProgram[i]->info.separate_shader) {
          pipe->InfoLog = ralloc_asprintf(pipe,
                                          "Program %d was relinked without "
                                          "PROGRAM_SEPARABLE state",
-                                         pipe->CurrentProgram[i]->Name);
-         goto err;
+                                         pipe->CurrentProgram[i]->Id);
+         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:
     *
@@ -821,17 +983,52 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
     *           maximum number of texture image units allowed."
     */
    if (!_mesa_sampler_uniforms_pipeline_are_valid(pipe))
-      goto err;
+      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;
-
-err:
-   if (IsBound)
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glValidateProgramPipeline failed to validate the pipeline");
-
-   return GL_FALSE;
 }
 
 /**
@@ -842,6 +1039,9 @@ _mesa_ValidateProgramPipeline(GLuint pipeline)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glValidateProgramPipeline(%u)\n", pipeline);
+
    struct gl_pipeline_object *pipe = _mesa_lookup_pipeline_object(ctx, pipeline);
 
    if (!pipe) {
@@ -850,8 +1050,7 @@ _mesa_ValidateProgramPipeline(GLuint pipeline)
       return;
    }
 
-   _mesa_validate_program_pipeline(ctx, pipe,
-                                   (ctx->_Shader->Name == pipe->Name));
+   _mesa_validate_program_pipeline(ctx, pipe);
 }
 
 void GLAPIENTRY
@@ -860,6 +1059,10 @@ _mesa_GetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize,
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glGetProgramPipelineInfoLog(%u, %d, %p, %p)\n",
+                  pipeline, bufSize, length, infoLog);
+
    struct gl_pipeline_object *pipe = _mesa_lookup_pipeline_object(ctx, pipeline);
 
    if (!pipe) {
@@ -874,8 +1077,5 @@ _mesa_GetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize,
       return;
    }
 
-   if (pipe->InfoLog)
-      _mesa_copy_string(infoLog, bufSize, length, pipe->InfoLog);
-   else
-      *length = 0;
+   _mesa_copy_string(infoLog, bufSize, length, pipe->InfoLog);
 }