mesa: fix empty program log length
[mesa.git] / src / mesa / main / pipelineobj.c
index c2e1d29ad80b52ee71ca8c82bcd770cb68fcb512..310b745ebc8f0d9e9613c18031f707e391f72088 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.
@@ -107,7 +107,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;
@@ -230,6 +230,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;
@@ -251,6 +255,8 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
    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)");
@@ -332,6 +338,11 @@ _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
 
    if ((stages & GL_TESS_EVALUATION_SHADER_BIT) != 0)
       _mesa_use_shader_program(ctx, GL_TESS_EVALUATION_SHADER, shProg, pipe);
+
+   if ((stages & GL_COMPUTE_SHADER_BIT) != 0)
+      _mesa_use_shader_program(ctx, GL_COMPUTE_SHADER, shProg, pipe);
+
+   pipe->Validated = false;
 }
 
 /**
@@ -345,6 +356,9 @@ _mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
    struct gl_shader_program *shProg = NULL;
    struct gl_pipeline_object *pipe = _mesa_lookup_pipeline_object(ctx, pipeline);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glActiveShaderProgram(%u, %u)\n", pipeline, program);
+
    if (program != 0) {
       shProg = _mesa_lookup_shader_program_err(ctx, program,
                                                "glActiveShaderProgram(program)");
@@ -380,6 +394,9 @@ _mesa_BindProgramPipeline(GLuint pipeline)
    GET_CURRENT_CONTEXT(ctx);
    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)
@@ -425,6 +442,7 @@ 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);
 
@@ -450,8 +468,8 @@ _mesa_bind_pipeline(struct gl_context *ctx,
 
       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++)
+         _mesa_shader_program_init_subroutine_defaults(ctx, ctx->_Shader->CurrentProgram[i]);
    }
 }
 
@@ -467,6 +485,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;
@@ -551,6 +572,9 @@ _mesa_GenProgramPipelines(GLsizei n, GLuint *pipelines)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glGenProgramPipelines(%d, %p)\n", n, pipelines);
+
    create_program_pipelines(ctx, n, pipelines, false);
 }
 
@@ -559,6 +583,9 @@ _mesa_CreateProgramPipelines(GLsizei n, GLuint *pipelines)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glCreateProgramPipelines(%d, %p)\n", n, pipelines);
+
    create_program_pipelines(ctx, n, pipelines, true);
 }
 
@@ -574,6 +601,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;
@@ -590,10 +620,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);;
+   const bool has_tess = _mesa_has_tessellation(ctx);
 
    if (!pipe) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -611,11 +645,11 @@ _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:
-      /* If pipeline is not bound, return initial value 0. */
-      *params = (ctx->_Shader->Name != pipe->Name) ? 0 : pipe->Validated;
+      *params = pipe->Validated;
       return;
    case GL_VERTEX_SHADER:
       *params = pipe->CurrentProgram[MESA_SHADER_VERTEX]
@@ -643,6 +677,12 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
       *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;
    }
@@ -721,10 +761,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;
 
@@ -752,7 +792,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;
       }
    }
 
@@ -773,7 +813,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
@@ -794,7 +834,7 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
            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
@@ -817,10 +857,33 @@ _mesa_validate_program_pipeline(struct gl_context* ctx,
                                          "Program %d was relinked without "
                                          "PROGRAM_SEPARABLE state",
                                          pipe->CurrentProgram[i]->Name);
-         goto err;
+         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:
     *
@@ -836,17 +899,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;
 
-   pipe->Validated = GL_TRUE;
-   return GL_TRUE;
+   /* 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;
 
-err:
-   if (IsBound)
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glValidateProgramPipeline failed to validate the pipeline");
+      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);
+   }
 
-   return GL_FALSE;
+   pipe->Validated = GL_TRUE;
+   return GL_TRUE;
 }
 
 /**
@@ -857,6 +955,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) {
@@ -865,8 +966,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
@@ -875,6 +975,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) {
@@ -889,8 +993,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);
 }