OSDN Git Service

glsl: support compilation of geometry shaders
authorBryan Cain <bryancain3@gmail.com>
Fri, 15 Feb 2013 15:46:50 +0000 (09:46 -0600)
committerPaul Berry <stereotype441@gmail.com>
Fri, 2 Aug 2013 03:20:45 +0000 (20:20 -0700)
This commit adds all of the parsing and semantics for GLSL 150 style
geometry shaders.

v2 (Paul Berry <stereotype441@gmail.com>): Add a few missing calls to
get_pipeline_stage().  Fix some signed/unsigned comparison warnings.
Fix handling of NULL consumer in assign_varying_locations().

v3 (Bryan Cain <bryancain3@gmail.com>): fix indexing order of 2D
arrays.  Also, allow interpolation qualifiers in geometry shaders.

v4 (Paul Berry <stereotype441@gmail.com>): Eliminate
get_pipeline_stage()--it is no longer needed thanks to 030ca23 (mesa:
renumber shader indices according to their placement in pipeline).
Remove 2D stuff.  Move vertices_per_prim() to ir.h, so that it will be
accessible from outside the linker.  Remove
inject_num_vertices_visitor.  Rework for GLSL 1.50.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
v5 (Paul Berry <stereotype441@gmail.com>): Split out
do_set_program_inouts() argument refactoring to a separate patch.
Move geom_array_resizing_visitor to later in the series.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/glsl/ast_to_hir.cpp
src/glsl/ir.cpp
src/glsl/ir.h
src/glsl/linker.cpp
src/mesa/main/mtypes.h

index 598da92..4b56452 100644 (file)
@@ -2056,12 +2056,12 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
       var->interpolation = INTERP_QUALIFIER_NONE;
 
    if (var->interpolation != INTERP_QUALIFIER_NONE &&
-       !(state->target == vertex_shader && var->mode == ir_var_shader_out) &&
-       !(state->target == fragment_shader && var->mode == ir_var_shader_in)) {
+       ((state->target == vertex_shader && var->mode == ir_var_shader_in) ||
+        (state->target == fragment_shader && var->mode == ir_var_shader_out))) {
       _mesa_glsl_error(loc, state,
-                      "interpolation qualifier `%s' can only be applied to "
-                      "vertex shader outputs and fragment shader inputs",
-                      var->interpolation_string());
+                       "interpolation qualifier `%s' cannot be applied to "
+                       "vertex shader inputs or fragment shader outputs",
+                       var->interpolation_string());
    }
 
    var->pixel_center_integer = qual->flags.q.pixel_center_integer;
@@ -2662,6 +2662,26 @@ ast_declarator_list::hir(exec_list *instructions,
 
       var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
 
+      /* The 'varying in' and 'varying out' qualifiers can only be used with
+       * ARB_geometry_shader4 and EXT_geometry_shader4, which we don't support
+       * yet.
+       */
+      if (this->type->qualifier.flags.q.varying) {
+         if (this->type->qualifier.flags.q.in) {
+            _mesa_glsl_error(& loc, state,
+                             "`varying in' qualifier in declaration of "
+                             "`%s' only valid for geometry shaders using "
+                             "ARB_geometry_shader4 or EXT_geometry_shader4",
+                             decl->identifier);
+         } else if (this->type->qualifier.flags.q.out) {
+            _mesa_glsl_error(& loc, state,
+                             "`varying out' qualifier in declaration of "
+                             "`%s' only valid for geometry shaders using "
+                             "ARB_geometry_shader4 or EXT_geometry_shader4",
+                             decl->identifier);
+         }
+      }
+
       /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification;
        *
        *     "Global variables can only use the qualifiers const,
@@ -2906,7 +2926,7 @@ ast_declarator_list::hir(exec_list *instructions,
             }
             break;
          default:
-            assert(0);
+            break;
          }
       }
 
index dad58de..99dceac 100644 (file)
@@ -1778,3 +1778,24 @@ ir_rvalue::as_rvalue_to_saturate()
 
    return NULL;
 }
+
+
+unsigned
+vertices_per_prim(GLenum prim)
+{
+   switch (prim) {
+   case GL_POINTS:
+      return 1;
+   case GL_LINES:
+      return 2;
+   case GL_TRIANGLES:
+      return 3;
+   case GL_LINES_ADJACENCY:
+      return 4;
+   case GL_TRIANGLES_ADJACENCY:
+      return 6;
+   default:
+      assert(!"Bad primitive");
+      return 3;
+   }
+}
index 4cb1202..62e3b27 100644 (file)
@@ -2128,4 +2128,7 @@ extern void _mesa_print_ir(struct exec_list *instructions,
 } /* extern "C" */
 #endif
 
+unsigned
+vertices_per_prim(GLenum prim);
+
 #endif /* IR_H */
index d7ea740..f25dca2 100644 (file)
 #include "linker.h"
 #include "link_varyings.h"
 #include "ir_optimization.h"
+#include "ir_rvalue_visitor.h"
 
 extern "C" {
 #include "main/shaderobj.h"
 }
 
+void linker_error(gl_shader_program *, const char *, ...);
+
 /**
  * Visitor that determines whether or not a variable is ever written.
  */
@@ -402,6 +405,24 @@ validate_fragment_shader_executable(struct gl_shader_program *prog,
    }
 }
 
+/**
+ * Verify that a geometry shader executable meets all semantic requirements
+ *
+ * Also sets prog->Geom.VerticesIn as a side effect.
+ *
+ * \param shader Geometry shader executable to be verified
+ */
+void
+validate_geometry_shader_executable(struct gl_shader_program *prog,
+                                   struct gl_shader *shader)
+{
+   if (shader == NULL)
+      return;
+
+   unsigned num_vertices = vertices_per_prim(prog->Geom.InputType);
+   prog->Geom.VerticesIn = num_vertices;
+}
+
 
 /**
  * Generate a string describing the mode of a variable
@@ -1613,11 +1634,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    unsigned num_vert_shaders = 0;
    struct gl_shader **frag_shader_list;
    unsigned num_frag_shaders = 0;
+   struct gl_shader **geom_shader_list;
+   unsigned num_geom_shaders = 0;
 
    vert_shader_list = (struct gl_shader **)
       calloc(prog->NumShaders, sizeof(struct gl_shader *));
    frag_shader_list = (struct gl_shader **)
       calloc(prog->NumShaders, sizeof(struct gl_shader *));
+   geom_shader_list = (struct gl_shader **)
+      calloc(prog->NumShaders, sizeof(struct gl_shader *));
 
    unsigned min_version = UINT_MAX;
    unsigned max_version = 0;
@@ -1643,8 +1668,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
         num_frag_shaders++;
         break;
       case GL_GEOMETRY_SHADER:
-        /* FINISHME: Support geometry shaders. */
-        assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER);
+        geom_shader_list[num_geom_shaders] = prog->Shaders[i];
+        num_geom_shaders++;
         break;
       }
    }
@@ -1706,6 +1731,22 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
                             sh);
    }
 
+   if (num_geom_shaders > 0) {
+      gl_shader *const sh =
+        link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list,
+                                num_geom_shaders);
+
+      if (!prog->LinkStatus)
+        goto done;
+
+      validate_geometry_shader_executable(prog, sh);
+      if (!prog->LinkStatus)
+        goto done;
+
+      _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+                            sh);
+   }
+
    /* Here begins the inter-stage linking phase.  Some initial validation is
     * performed, then locations are assigned for uniforms, attributes, and
     * varyings.
@@ -1792,7 +1833,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
             prog->_LinkedShaders[MESA_SHADER_VERTEX],
             VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0);
    }
-   /* FINISHME: Geometry shaders not implemented yet */
+   if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
+      link_invalidate_variable_locations(
+            prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+            VARYING_SLOT_VAR0, VARYING_SLOT_VAR0);
+   }
    if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
       link_invalidate_variable_locations(
             prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
@@ -1826,7 +1871,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
        *     non-zero, but the program object has no vertex or geometry
        *     shader;
        */
-      if (first >= MESA_SHADER_FRAGMENT) {
+      if (first == MESA_SHADER_FRAGMENT) {
          linker_error(prog, "Transform feedback varyings specified, but "
                       "no vertex or geometry shader is present.");
          goto done;
@@ -1950,6 +1995,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 done:
    free(vert_shader_list);
    free(frag_shader_list);
+   free(geom_shader_list);
 
    for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
       if (prog->_LinkedShaders[i] == NULL)
index 91c3abf..c78fe85 100644 (file)
@@ -1852,7 +1852,7 @@ struct gl_program
    GLuint Id;
    GLubyte *String;  /**< Null-terminated program text */
    GLint RefCount;
-   GLenum Target;    /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB */
+   GLenum Target;    /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_GEOMETRY_PROGRAM_NV */
    GLenum Format;    /**< String encoding format */
 
    struct prog_instruction *Instructions;
@@ -1919,6 +1919,7 @@ struct gl_geometry_program
 {
    struct gl_program Base;   /**< base class */
 
+   GLint VerticesIn;
    GLint VerticesOut;
    GLenum InputType;  /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
                            GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */
@@ -2321,6 +2322,7 @@ struct gl_shader_program
 
    /** Geometry shader state - copied into gl_geometry_program at link time */
    struct {
+      GLint VerticesIn;
       GLint VerticesOut;
       GLenum InputType;  /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
                               GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */