Name

    NV_geometry_shader_passthrough

Name Strings

    GL_NV_geometry_shader_passthrough

Contact

    Pat Brown, NVIDIA Corporation (pbrown 'at' nvidia.com)

Contributors

    Jeff Bolz, NVIDIA Corporation
    Piers Daniell, NVIDIA Corporation
    Christoph Kubisch, NVIDIA Corporation
    Mathias Heyer, NVIDIA Corporation
    Mark Kilgard, NVIDIA Corporation

Status

    Shipping

Version

    Last Modified Date:         April 6, 2015
    NVIDIA Revision:            3

Number

    OpenGL Extension #470
    OpenGL ES Extension #233

Dependencies

    This extension is written against the OpenGL 4.3 Specification
    (Compatibility Profile), dated February 14, 2013

    This extension is written against the OpenGL Shading Language
    Specification, version 4.30, revision 8.

    OpenGL ES 3.1 and EXT_geometry_shader are required for an
    implementation in OpenGL ES.

    This extension interacts with OpenGL 4.4 and ARB_enhanced_layouts.

    This extension interacts with NV_gpu_program4 and NV_gpu_program5.

    This extension interacts with NV_geometry_shader4 and NV_gpu_shader4.

    This extension interacts with NV_geometry_program4 and NV_gpu_program4.

    This extension interacts with NV_transform_feedback.

    This extension interacts with a combination of NV_gpu_program4,
    NV_gpu_program5, NV_transform_feedback, EXT_transform_feedback, and OpenGL
    3.0.

    This extension interacts with NVX_shader_thread_group.

Overview

    Geometry shaders provide the ability for applications to process each
    primitive sent through the GL using a programmable shader.  While geometry
    shaders can be used to perform a number of different operations, including
    subdividing primitives and changing primitive type, one common use case
    treats geometry shaders as largely "passthrough".  In this use case, the
    bulk of the geometry shader code simply copies inputs from each vertex of
    the input primitive to corresponding outputs in the vertices of the output
    primitive.  Such shaders might also compute values for additional built-in
    or user-defined per-primitive attributes (e.g., gl_Layer) to be assigned
    to all the vertices of the output primitive.

    This extension provides a shading language abstraction to express such
    shaders without requiring explicit logic to manually copy attributes from
    input vertices to output vertices.  For example, consider the following
    simple geometry shader in unextended OpenGL:

      layout(triangles) in;
      layout(triangle_strip) out;
      layout(max_vertices=3) out;

      in Inputs {
        vec2 texcoord;
        vec4 baseColor;
      } v_in[];
      out Outputs {
        vec2 texcoord;
        vec4 baseColor;
      };

      void main()
      {
        int layer = compute_layer();
        for (int i = 0; i < 3; i++) {
          gl_Position = gl_in[i].gl_Position;
          texcoord = v_in[i].texcoord;
          baseColor = v_in[i].baseColor;
          gl_Layer = layer;
          EmitVertex();
        }
      }

    In this shader, the inputs "gl_Position", "Inputs.texcoord", and
    "Inputs.baseColor" are simply copied from the input vertex to the
    corresponding output vertex.  The only "interesting" work done by the
    geometry shader is computing and emitting a gl_Layer value for the
    primitive.

    The following geometry shader, using this extension, is equivalent:

      #extension GL_NV_geometry_shader_passthrough : require

      layout(triangles) in;
      // No output primitive layout qualifiers required.

      // Redeclare gl_PerVertex to pass through "gl_Position".
      layout(passthrough) in gl_PerVertex {
        vec4 gl_Position;
      } gl_in[];

      // Declare "Inputs" with "passthrough" to automatically copy members.
      layout(passthrough) in Inputs {
        vec2 texcoord;
        vec4 baseColor;
      } v_in[];

      // No output block declaration required.

      void main()
      {
        // The shader simply computes and writes gl_Layer.  We don't
        // loop over three vertices or call EmitVertex().
        gl_Layer = compute_layer();
      }

New Procedures and Functions

    None.

New Tokens

    None.

Modifications to the OpenGL 4.3 Specification (Compatibility Profile)

    Modify Section 11.3.4.5, Geometry Shader Outputs, p. 425

    (add to the end of the section, p. 426):

    For the purposes of component counting, passthrough geometry shaders count
    all active input variable components declared with the layout qualifier
    "passthrough" as output components as well, since their values will be
    copied to the output primitive produced by the geometry shader.


Modifications to the OpenGL Shading Language Specification, Version 4.30

    Including the following line in a shader can be used to control the
    language features described in this extension:

      #extension GL_NV_geometry_shader_passthrough : <behavior>

    where <behavior> is as specified in section 3.3.

    New preprocessor #defines are added to the OpenGL Shading Language:

      #define GL_NV_geometry_shader_passthrough         1

    Modify Section 4.4.1.2, Geometry Shader Inputs (p. 57)

    (add to the list of allowed layout qualifiers, p. 57)

      layout-qualifier-id
        ...
        passthrough

    (insert after discussion of the "invocations" layout qualifier, p. 57)

    A geometry shader using the layout qualifier "passthrough" is considered a
    "passthrough geometry shader".  Output primitives in a passthrough
    geometry shader always have the same topology as the input primitive and
    are not produced by emitting vertices.  The vertices of the output
    primitive have two different types of attributes.  Geometry shader inputs
    qualified with "passthrough" are considered to produce per-vertex outputs,
    where values for each output vertex are copied from the corresponding
    input vertex.  Any built-in or user-defined geometry shader outputs are
    considered per-primitive in a passthrough geometry shader, where a single
    output value is copied to all output vertices.

    The identifier "passthrough" can not be used to qualify "in", but can be
    used to qualify input variables, blocks, or block members.  It specifies
    that values of those inputs will be copied to the corresponding vertex of
    the output primitive.  Input variables and block members not qualified
    with "passthrough" will be consumed by the geometry shader without being
    passed through to subsequent stages.  For the purposes of matching
    passthrough geometry shader inputs with outputs of the previous pipeline
    stages, the "passthrough" qualifier itself is ignored.  For separable
    program objects (where geometry shader inputs and outputs may interface
    with inputs and outputs in other program objects), all inputs qualified
    with "passthrough" must also be assigned a location using the "location"
    layout qualifier.  It is a link-time error to specify a passthrough
    geometry shader input in a separable program without an explicitly
    assigned location.

    For the purposes of matching the outputs of the geometry shader with
    subsequent pipeline stages, each input qualified with "passthrough" is
    considered to add an equivalent output with the same name, type, and
    qualification (except using "out" instead of "in") on the output
    interface.  The output declaration corresponding to an input variable
    qualified with "passthrough" will be identical to the input declaration,
    except that it will not be treated as arrayed.  The output block
    declaration corresponding to an input block qualified with "passthrough"
    or having members qualified with "passthrough" will be identical to the
    input declaration, except that it will not be treated as arrayed and will
    not have an instance name.  If an input block is qualified with
    "passthrough", the equivalent output block contains all the members of the
    input block.  Otherwise, the equivalent output block contains only those
    input block members qualified with "passthrough".  If such an input block
    is qualified with "location" or has members qualified with "location", all
    members of the corresponding output block members are assigned locations
    identical to those assigned to corresponding input block members.  All
    such outputs are associated with output vertex stream zero (section
    4.4.2.2).  Output variables and blocks generated from inputs qualified
    with "passthrough" will only be added to the name space of the output
    interface; these declarations will not be available to geometry shader
    code.  A program will fail to link if it contains a geometry shader output
    block with the same name as a geometry shader input block that is
    qualified with "passthrough" or contains a member qualified with
    "passthrough".

    A compile-time error is generated if the non-arrayed input variables
    "gl_PrimitiveIDIn" or "gl_InvocationID" are redeclared with the
    "passthrough" layout qualifier.

    A compile- or link-time error will be generated if a program contains a
    passthrough geometry shader and:

      * declares a geometry shader input primitive type using layout
        qualifiers other than "points", "lines", or "triangles";

      * declares a geometry shader output primitive type using the output
        layout qualifiers "points", "line_strip", or "triangle_strip" (section
        4.4.2.2);

      * declares a geometry shader output primitive vertex count using the
        output layout qualifier "max_vertices";

      * declares a geometry shader invocation count other than one using the
        input layout qualifier "invocations";

      * declares a geometry shader output variable or block qualified with
        "stream" with an associated output vertex stream other than zero;

      * includes geometry shader code calling the built-in functions
        EmitVertex(), EmitStreamVertex(), EndPrimitive(), or
        EndStreamPrimitive(); or

      * is configured to use transform feedback, using either the geometry
        shader output layout qualifiers "xfb_offset", "xfb_stride", and
        "xfb_buffer", or using the OpenGL API command
        TransformFeedbackVaryings().

    For the purposes of OpenGL API queries, passthrough geometry shaders are
    considered to include an output layout qualifier (section 4.4.2.2)
    specifying an output primitive type and maximum vertex count consistent
    with an equivalent non-passthrough geometry shader, as per the following
    table.

        Input Layout            Output Layout
        ----------------        ------------------------------------------
        points                  layout(points, max_vertices=1) out;
        lines                   layout(line_strip, max_vertices=2) out;
        triangles               layout(triangle_strip, max_vertices=3) out;

Additions to the AGL/GLX/WGL Specifications

    None.

Errors

    None.

New State

    None.

New Implementation Dependent State

    None.


Interactions with OpenGL ES 3.1

    Unless made available by functionality similar to ARB_transform_feedback3
    and ARB_gpu_shader5, remove references to EmitStreamVertex() and
    EndStreamPrimitive(), the "stream = N" layout qualifier as well as
    the notion of multiple transform feedback streams.

Dependencies on OpenGL 4.4 and ARB_enhanced_layouts

    If neither OpenGL 4.4 nor ARB_enhanced_layouts is supported, remove
    references to the use of the "xfb_offset", "xfb_buffer", and "xfb_stride"
    layout qualifiers for transform feedback.

Dependencies on NV_gpu_program4 and NV_geometry_program4

    Modify Section 2.X.2, Program Grammar, of the NV_geometry_program4
    specification (which modifies the NV_gpu_program4 base grammar)

    <declaration>               ::= "PASSTHROUGH" <resultUseD> <optWriteMask>

    Modify Section 2.X.6, Program Options

    + Passthrough Geometry Program (NV_geometry_program_passthrough)

    If a geometry program specifies the "NV_geometry_program_passthrough"
    option, the program will be configured as a passthrough geometry program.
    A passthrough geometry program is configured to emit a new output
    primitive with the same type and vertex count as its input primitive.  For
    any result variable components written by a passthrough geometry program
    instruction, the values are broadcast to all vertices of the output
    primitive.  For any result binding components specified in PASSTHROUGH
    statements, the component values for each input primitive vertex are
    copied ("passed through") to their corresponding output primitive vertex
    without requiring geometry program code to copy attribute values and emit
    output primitive vertices.  A passthrough geometry program will fail to
    load if it contains an INVOCATIONS, PRIMITIVE_OUT, or VERTICES_OUT
    declaration, or an EMIT, EMITS, or ENDPRIM instruction.  A passthrough
    geometry program must declare an input primitive type of POINTS, LINES, or
    TRIANGLES, and the resulting output primitive produced will be a single
    point, line, or triangle, respectively.  The PASSTHROUGH declaration can
    be used only in programs using this option.


    Section 2.X.7.Y, Geometry Program Declarations

    (modify the first paragraph of the section)

    Geometry programs support three types of declaration statements specifying
    input and output primitive types, as described below. ....

    (add to the end of the section)

    Additionally, if the "NV_geometry_program_passthrough" option is
    specified, a geometry program can include zero or more instances of the
    following declaration statement:

    - Passthrough Geometry Shader Attribute (PASSTHROUGH)

    Each PASSTHROUGH declaration statement identifies a set of result binding
    components whose values for each vertex of the output primitive will be
    produced by copying the corresponding attribute binding components from
    the corresponding vertex of the input primitive.  The set of result
    bindings for which this copy is performed is identified by the
    <resultUseD> grammar rule.  For each such binding, the set of components
    to be copied is identified by the <optWriteMask> grammar rule.  If the
    write mask is omitted, all components of each binding are copied.  A
    program will fail to load if the binding identified by the <resultUseD>
    grammar rule does not have a corresponding attribute binding;
    "result.primid", "result.layer", and "result.viewport" may not be used.
    It is legal to specify an attribute binding more than once in a
    PASSTHROUGH declaration; a component will be passed through if and only if
    it is identified in one or more PASSTHROUGH declarations.  A program will
    fail to load if any result binding is both declared in a PASSTHROUGH
    statement and written by a program instruction, even if the set of
    components referenced is mutually exclusive.

    Modify Section 13.2.2 of the OpenGL 4.3 Specification, p. 457

    (insert before the errors section, p. 458)

    Transform feedback can not be used with passthrough geometry programs.
    When transform back is active and not paused, an INVALID_OPERATION error
    is generated by any command that transfers vertices to the GL if the
    current geometry program was declared using the
    "NV_geometry_shader_passthrough" program option.


Dependencies on NV_geometry_shader4 and NV_gpu_shader4

    If NV_geometry_shader4 is supported, it is possible to change the maximum
    geometry shader output vertex count after linking a program.  The
    following language should be added to the end of the description of the
    the GEOMETRY_VERTICES_OUT_EXT <pname> for the ProgramParameteriEXT API in
    the NV_geometry_shader4 specification:

      The error INVALID_OPERATION is generated by ProgramParameteriEXT if
      <program> identifies a program object that has been linked successfully
      and includes a passthrough geometry shader (one using the "passthrough"
      layout qualifier).

    Note that NV_geometry_shader4 doesn't have its own extension string entry;
    it is considered present if and only if NV_gpu_shader4 is advertised.

Dependencies on NV_geometry_program4 and NV_gpu_program4

    If NV_geometry_program4 is supported, it is possible to change the maximum
    output vertex count after compiling an assembly geometry program.  The
    following language should be added to the end of the description of the
    ProgramVertexLimitNV API:

      The error INVALID_OPERATION is generated by ProgramVertexLimitNV if the
      current geometry program uses the NV_geometry_program_passthrough
      program option.

    Note that NV_geometry_program4 doesn't have its own extension string
    entry; it is considered present if and only if NV_gpu_program4 is
    advertised.

Dependencies on NV_transform_feedback

    If NV_transform_feedback is supported, the following language should be
    added to the end of the description of the TransformFeedbackVaryingsNV
    API:

      The error INVALID_OPERATION is generated by TransformFeedbackVaryingsNV
      if <program> identifies a program containing a passthrough geometry
      shader (i.e., one using the "passthrough" layout qualifier).

Dependencies on NV_gpu_program4, NV_gpu_program5, NV_transform_feedback,
EXT_transform_feedback, and OpenGL 3.0:

    If NV_gpu_program4 and/or NV_gpu_program5 is supported together with any
    of NV_transform_feedback, EXT_transform_feedback, or OpenGL 3.0 is
    supported, the following language should be added to the descriptions of
    BeginTransformFeedbackNV(), BeginTransformFeedbackEXT(), and
    BeginTransformFeedback() as applicable:

      Transform feedback is not supported with passthrough geometry programs.
      The error INVALID_OPERATION error is generated if there is an active
      geometry program that uses the NV_geometry_program_passthrough program
      option.

    Note that this issue doesn't apply to GLSL program objects, since we are
    making it impossible to successfully specify a program that uses transform
    feedback and a passthrough geometry shader concurrently.

Dependencies on NVX_shader_thread_group

    If NVX_shader_thread_group is supported, the new built-in inputs provided
    by that extension should not be allowed as passthrough:

      A compile-time error is generated if any of the non-arrayed input
      variables "gl_PrimitiveIDIn", "gl_InvocationID", "gl_ThreadInWarpNVX",
      "gl_ThreadEqMaskNVX", "gl_ThreadGeMaskNVX", "gl_ThreadGtMaskNVX",
      "gl_ThreadLeMaskNVX", "gl_ThreadLtMaskNVX", "gl_WarpIDNVX", or
      "gl_SMIDNVX" are redeclared with the "passthrough" layout qualifier.


Issues

    (1) What should this extension be called?

      RESOLVED:  NV_geometry_shader_passthrough.  The new layout qualifier
      specifies new semantics where primitives are largely "passed through" by
      the geometry shader, copying vertices of the input primitive to the
      output primitive.  The only operation performed by geometry shaders
      using this extension is to compute a collection of per-primitive
      attributes assigned to all vertices of the geometry shader.

    (2) This extension is aimed at geometry shaders that show a specific
        pattern.  Why provide an explicit programming model in this extension,
        as opposed to automatically optimizing regular geometry shaders?

      RESOLVED:  The hardware for which this extension was written provides
      explicit support for passing attributes of geometry shader input
      vertices through the geometry stage without an explicit copy.  While
      implementations supporting this extension may optimize geometry shaders
      to use this hardware, we provide an explicit programming model because
      (a) application developers may prefer to use this model for programming
      such shaders and (b) automatic optimization may fail to detect a
      "passthrough" pattern in some geometry shaders.

    (3) How do passthrough geometry shaders interact with GLSL built-in
        variables?

      RESOLVED:  Geometry shaders can redeclare the built-in input block
      "gl_PerVertex" with the "passthrough" layout qualifier to specify that
      built-in inputs like "gl_Position" should be passed through.  We allow
      the shader to qualify the entire redeclared block with "passthrough" to
      pass through all block members.  We also allow the shader to qualify
      individual block members with "passthrough" to pass through some, but
      not all, block members.

    (4) How do passthrough geometry shaders interact with geometry shader
        instancing (using the "invocations=N" layout qualifier)?

      RESOLVED:  We disallow the use of instancing in passthrough geometry
      shaders; it will result in a link error.

      We considered specifying the features as orthogonal (with the
      passthrough geometry shader run N times), but consider the feature to be
      of limited utility.  Making N separate copies of the input primitive
      type isn't consistent with a model that largely passes through one
      single primitive.

    (5) How do passthrough geometry shaders interact with transform feedback?

      RESOLVED:  We disallow the use of transform feedback with programs with
      a passthrough geometry shader; it will result in a link error.

      We considered specifying the features as orthogonal, but consider the
      feature to be of limited utility.  In particular, since inputs that are
      passed through the geometry shader don't have explicit output
      declarations, there is no way to control transform feedback using the
      "xfb_offset", "xfb_buffer", and "xfb_stride" layout qualifiers.  While
      it would still be possible to use the OpenGL API command
      TransformFeedbackVaryings() to specify passed through inputs to capture,
      we decided it wasn't worth the trouble.

      For GLSL programs in unextended OpenGL 4.3, we can specify a link-time
      error to enforce this limitation.  For applications using GLSL programs
      and the NV_transform_feedback extension (where transform feedback
      varyings can be specified post-link), we throw an error when attempting
      to update transform feedback.  We will also prohibit the use of assembly
      programs with transform feedback for consistency, but need to specify a
      Draw-time error for that since transform feedback is completely
      decoupled from assembly program objects.

    (6) How do passthrough geometry shaders interact with multi-stream
        geometry shader support (using the "stream=N" layout qualifier)?

      RESOLVED:  All of the output vertices of a passthrough geometry shader
      are associated with output vertex stream zero.  Additionally, it is an
      error to declare a GLSL output variable with a stream other than zero.

    (7) Do passthrough geometry shaders need to use layout qualifiers
        describing the output primitive type?

      RESOLVED:  No.  We will not allow the use of these layout qualifiers
      with passthrough geometry shaders.  The output primitive type and vertex
      count will be taken directly from the input primitive type for such
      shaders.

    (8) Inputs qualified with "passthrough" are copied to the vertices of the
        output primitive.  Do they show up on the PROGRAM_OUTPUT interface for
        program resource queries (e.g., GetProgramResourceiv)?

      RESOLVED:  Yes, passed through variables, blocks, and block members
      appear on the output interface.

    (9) How should geometry shaders indicate that they want to be
        "passthrough"?  Should we have some sort of declaration at global
        scope (e.g., "layout(passthrough) in") or infer it from the presence
        of one or more layout qualifiers on variables, blocks, or block
        members?

      RESOLVED:  We consider a geometry shader to be passthrough if one or
      more input variables, blocks, or block members are qualified by
      "passthrough".  We won't require or allow the "passthrough" layout
      qualifier to be used on "in".

      We considered requiring separate declarations for a global "passthrough"
      mode and passing through individual variables like this:

        layout(passthrough) in;         // makes the shader passthrough

        layout(passthrough) in Block {  // pass through the contents of <Block>
          ...
        } v_in[];

      We decided not to do this in part because the inheritance semantics for
      other layout qualifiers might cause the casual programmer to expect that
      the applying the qualifier "passthrough" to in might cause all
      subsequent inputs to inherit "passthrough" behavior.

        layout(passthrough) in;
        in Block {
          ...
        } v_in[];

      We could have resolved this by using a second identifier (e.g.,
      "passthrough_shader") in the layout qualifier, but there don't seem to
      be any interesting cases where a passthrough geometry shader has no
      per-vertex outputs.  In particular, we expect pass-through geometry
      shaders to always pass through "gl_Position".

    (10) Should we provide any query in the OpenGL API to determine whether a
         geometry shader is a "passthrough" shader?

      RESOLVED:  We are not going to bother to do so in this extension; there
      are numerous other optional shader features lacking such query support.

    (11) Should passthrough geometry shaders be allowed to write per-primitive
         values for arbitrary shader outputs or just the inherently
         per-primitive built-in outputs (e.g., gl_Layer, gl_ViewportIndex)?

      RESOLVED:  We should allow passthrough geometry shaders to write to both
      built-in and user-defined outputs.  Any output variables declared in
      passthrough geometry shader without the "passthrough" layout qualifier
      are treated as per-primitive outputs and will be broadcast to all
      vertices in the output primitive.  For example, this shader

        layout(passthrough) in;
        layout(passthrough) in gl_PerVertex {
          vec4 gl_Position;
        } gl_in[];
        out vec4 batman;

        void main()
        {
          batman = compute_batman();
        }

      will attach the value produced by compute_batman() to all the vertices
      of the output primitive.  The value of gl_Position for each vertex of
      the output primitive will be copied directly from the value of
      gl_Position for the corresponding input vertex.

    (12) How do per-primitive outputs from passthrough geometry shaders
         interact with fragment shader inputs?

      RESOLVED:  Per-primitive outputs will be broadcast to all the vertices
      of the output primitive, so reading the corresponding fragment shader
      input should yield the per-primitive output value.

      We strongly recommend using the "flat" qualifier on all fragment shader
      inputs corresponding to per-primitive passthrough geometry shader
      outputs.  Using "flat" on such inputs may result in better performance
      when using passthrough geometry shaders.

      We also recommend using the "flat" qualifier on such inputs to avoid
      possible arithmetic error that can result from evaluating
      perspective-correct interpolation equations.  For example,
      perspective-correct attribute interpolation for triangles uses the
      equation:

        f = (a*f_a/w_a + b*f_b/w_b + c*f_c/w_c) / (a/w_a + b/w_b + c/w_c)

      where a, b, and c are interpolation weights (adding to 1), f_a, f_b, and
      f_c are per-vertex attribute values, and w_a, w_b, and w_c are
      per-vertex clip w coordinates.  For per-primitive outputs, f_a == f_b ==
      f_c, which equals the per-primitive attribute value f_p, so the equation
      simplifies to:

        f = (a*f_p/w_a + b*f_p/w_b + c*f_p/w_c) / (a/w_a + b/w_b + c/w_c)
          = f_p * (a/w_a + b/w_b + c/w_c) / (a/w_a + b/w_b + c/w_c)

      At infinite precision, this computation will produce f_p, however there
      may be rounding error from the division operators that could result in
      low-order bit differences in the final interpolated value.

    (13) What values are returned for queries of geometry shader-related
         program properties that are not specified passthrough geometry
         shaders (GEOMETRY_OUTPUT_TYPE, GEOMETRY_VERTICES_OUT)?

      RESOLVED:  We will return values consistent with the input primitive
      type, as though a non-passthrough geometry shader were specified.  For
      example, if the input primitive type is "triangles", the shader will be
      treated as having declared:

        layout(triangle_strip, max_vertices=3) out;

    (14) Do passed through outputs count against the limit of total geometry
         shader output components?  What about the limit on the product of
         per-vertex components and vertices emitted?

      RESOLVED:  Yes, we still want a limit on the total number of components
      in each output vertex.  Input components qualified by "passthrough" are
      also counted as output components for the purposes of both limit checks.
      We expect that the latter limit (on the product) will never be relevant
      because the total number of vertices in the output primitive can be at
      most three.

    (15) How does this extension interact with the ability to change geometry
         shader output vertex counts, using ProgramParameteriEXT with
         GEOMETRY_VERTICES_OUT_EXT for GLSL programs (NV_geometry_shader4) or
         ProgramVertexLimitNV API for assembly programs
         (NV_geometry_program4)?

      RESOLVED:  These commands allow applications to override the declared
      maximum output vertex counts for geometry shaders based on information
      known at runtime.  Given that passthrough geometry shaders (and assembly
      programs) will fail if they declare an output vertex count, it makes no
      sense to override a declaration that doesn't exist.  We will throw
      INVALID_OPERATION if you try to use these APIs with passthrough geometry
      shaders.

    (16) Does this extension interact with separable program objects?

      RESOLVED:  Yes.  All geometry shader inputs qualified with the
      "passthrough" layout qualifier must also have a location explicitly
      assigned using the "location" layout qualifier.  Failing to do so will
      result in a link-time error.

      The reason for this restriction is that inputs/outputs of one separable
      program object may interface at run time with inputs/outputs of a
      different separable program object.  When linking one separable program
      object, the GL has no idea what other program objects it may be used
      with.  To avoid requiring GL implementations to dynamically link program
      objects X and Y at run time when they are used together, unextended
      OpenGL requires an "interface match" to get defined results passing
      values between stages.  Basically, the outputs of program X and inputs
      of program Y are considered to match:

        * for entire programs, if the set of declared inputs and outputs in
          the programs are identical in name (or location, if assigned), type,
          and qualification; or

        * for individual inputs, if the input has a matching output with
          compatible type and qualification, if both variables use the same
          location layout qualifier.

      The idea behind the exact matching requirement is that if you have
      identical declarations on both sides of the interface, the
      compiler/linker can employ a deterministic algorithm to assign locations
      internally, based solely on the declared inputs/outputs.  For such an
      algorithm, the variables on both sides of the interface will naturally
      get the same locations.  For a program pipeline with separate vertex,
      geometry, and fragment programs with "entire program" matches, this
      implies that:

        * vertex outputs and geometry inputs are declared identically, and so
          the compiler will assign the same locations; and

        * geometry outputs and fragment inputs are declared identically, and
          so the compiler will assign the same locations.

      The problem with this extension is that its implementation introduces
      one additional constraint -- the internal location assigned to a
      passthrough geometry shader input must match the location assigned to
      the matching implicitly-declared output.  Adding this constraint to the
      two bullets in the previous example implies that for any variable used
      as a passthrough input in a geometry shader, there is one additional
      rule:

        * the vertex outputs and fragment inputs matching a passthrough
          geometry shader input must have the same locations.

      However, when the vertex and fragment program are linked, they have no
      idea which variables might interface with a passthrough geometry shader
      input.  And there is clearly no constraint that the vertex outputs and
      fragment inputs be declared identically -- some vertex outputs may be
      consumed by the geometry shader, and some fragment inputs may be
      produced (not by copy) by the geometry shader.  Generating matching
      locations without more information is basically impossible.

      As a result, we require that the passthrough geometry shader inputs in
      separable programs must be declared with a location.  Combining this
      restriction with normal shader interface matching rules, it implies that
      "matching" vertex outputs and fragment inputs must also be declared with
      identical locations to get a complete interface match.

      This limitation doesn't apply to non-separable programs; the linker is
      able to see all program interfaces and can assign internal locations for
      all stages that satisfy the relevant constraints.  The linker could
      successfully assign internal locations for separable programs containing
      multiple stages (e.g., GS+FS with no VS), but we chose to apply this
      restriction to all separable programs for simplicity.

    (17) When an input block or any of its members is qualified with
         "passthrough", this extension creates an implicitly declared
         corresponding output block containing all members to be passed
         through.  How does this feature interact with the "location" layout
         qualifier?

      RESOLVED:  All members of the output block are treated as having
      explicitly assigned locations inherited from matching input block
      members.  For example, if you had a geometry shader input block declared
      as:

        layout(location=0) in Block {
          layout(passthrough) vec4 a;  // assigned location 0
                              vec4 b;  // assigned location 1
          layout(passthrough) vec4 c;  // assigned location 2
        } v_in[];

      the corresponding output block is treated as though it were declared as:

        out Block {
          layout(location=0) vec4 a;
          layout(location=2) vec4 c;
        };

      A fragment shader matching with such a shader must include a similar
      input block declaration to get a complete interface match.

      To avoid the need to use location layout qualifiers on a
      member-by-member basis, a shader author using blocks with location
      qualifiers could choose to segregate passthrough and other inputs into
      separate blocks.  Alternately, all the passthrough inputs could be
      placed at the beginning of the geometry input block, which would result
      in a "normal" output block, except that the non-passthrough inputs would
      be dropped.

    (18) Do built-in or user-defined inputs qualified with "passthrough" need
         to be "arrayed"?

      RESOLVED:  Yes.  Normal geometry shader inputs must be declared in
      "arrayed" form, where each vertex has its own set of inputs.  Blocks
      must be declared as an array of instances:

        in Block {
          vec4 a;
        } v_in[];

      and non-block inputs must be declared as arrays:

        in vec4 a[];  // <a> is indexed by input vertex number

      It is illegal to declare non-arrayed geometry shader inputs, since it
      wouldn't be clear which vertex to use when accessing such inputs.

      Passthrough geometry shaders don't change this requirement.
      Additionally, the requirement still applies even if no code in the
      passthrough geometry shader reads from the input.  Note that in older
      versions of this specification, some examples declared passthrough
      inputs that were missing the per-vertex array declaration.

Revision History

    Revision 4, 2017/02/15 (pbrown)
      - Fix syntax issues in various sample code, including the introduction.
        Passthrough inputs need to be declared as "arrayed" (with a separate
        block instance for each vertex).  Added issue (18) to clarify further.

    Revision 3, 2015/04/06 (mjk)
      - Fix typos

    Revision 2, 2015/03/27
      - Add ES interactions

    Revision 1
      - Internal revisions.

