Name

    EXT_fragment_shading_rate

Name Strings

    GL_EXT_fragment_shading_rate
    GL_EXT_fragment_shading_rate_primitive
    GL_EXT_fragment_shading_rate_attachment

Contributors

    Jan-Harald Fredriksen, Arm
    Ralph Potter, Samsung
    Tate Hornbeck, Qualcomm
    Laurie Hedge, Imagination Technologies
    Contributors to QCOM_shading_rate
    Jingwen Wang, AMD

Contact

    Jan-Harald Fredriksen (jan-harald.fredriksen 'at' arm.com)
    Jingwen Wang (jingwewa 'at' amd.com)

Status

    Complete

Version

    Last Modified Date: October 15, 2025
    Revision: #4

Number

    OpenGL Extension #561
    OpenGL ES Extension #340

Dependencies

    OpenGL 3.0 or OpenGL ES 2.0 is required.

    This extension is written against the OpenGL 4.6 Core and OpenGL ES 3.2
    specifications.

    This extension interacts with OVR_multiview.

    This extension interacts with QCOM_framebuffer_foveated and
    QCOM_texture_foveated.

    This extension interacts with EXT_shader_pixel_local_storage and
    EXT_shader_pixel_local_storage2.

    When the GL_EXT_fragment_shading_rate extension or the
    GL_EXT_fragment_shading_rate_attachment extension is advertised, the
    implementation must also advertise either GLSL extension
    "GL_EXT_fragment_shading_rate" or GLSL extension
    "GL_EXT_fragment_invocation_density" (both documented separately).
    The GLSL extensions provide built-in variables that allow fragment shaders
    to determine the effective shading rate used for fragment invocations.

    When the GL_EXT_fragment_shading_rate_primitive extension is advertised,
    the implementation must also advertise GLSL extension
    "GL_EXT_fragment_shading_rate" (documented separately), which provides new
    built-in variables that allow vertex and geometry shaders to specify the
    fragment shading rate per primitive and also allow fragment shaders to
    determine the effective shading rate used for fragment invocations.

Overview

    By default, OpenGL runs a fragment shader once for each pixel covered by a
    primitive being rasterized. When using multisampling, the outputs of that
    fragment shader are broadcast to each covered sample of the fragment's
    pixel. When using multisampling, applications can optionally request that
    the fragment shader be run once per color sample (e.g., by using the
    "sample" qualifier on one or more active fragment shader inputs), or run a
    minimum number of times per pixel using SAMPLE_SHADING enable and the
    MinSampleShading frequency value.

    This extension allows applications to specify fragment shading rates of less
    than 1 invocation per pixel. Instead of invoking the fragment shader
    once for each covered pixel, the fragment shader can be run once for a
    group of adjacent pixels in the framebuffer. The outputs of that fragment
    shader invocation are broadcast to each covered sample for all of the pixels
    in the group. The initial version of this extension allows for groups of
    1, 2, 4, 8, and 16 pixels.

    This can be useful for effects like motion volumetric rendering where a
    portion of the scene is processed at full shading rate and a portion can be
    processed at a reduced shading rate, saving power and processing resources.
    The requested rate can vary from (finest and default) 1 fragment shader
    invocation per pixel to (coarsest) one fragment shader invocation for each
    4x4 block of pixels.

New Procedures and Functions

    void ShadingRateEXT(enum rate);
    void ShadingRateCombinerOpsEXT(enum combinerOp0, enum combinerOp1);
    void FramebufferShadingRateEXT(enum target, enum attachment, uint texture,
                                   int baseLayer, sizei numLayers,
                                   sizei texelWidth, sizei texelHeight);
    void GetFragmentShadingRatesEXT(sizei samples, sizei maxCount,
                                    sizei *count, enum *shadingRates);

New Tokens

    Accepted by the <attachment> parameter of FramebufferShadingRateEXT and
    GetFramebufferAttachmentParameteriv:

        SHADING_RATE_ATTACHMENT_EXT                             0x96D1

    Allowed in the <rate> parameter of ShadingRateEXT; returned by the
    <shadingRates> parameter of GetFragmentShadingRatesEXT:
        SHADING_RATE_1X1_PIXELS_EXT                             0x96A6
        SHADING_RATE_1X2_PIXELS_EXT                             0x96A7
        SHADING_RATE_1X4_PIXELS_EXT                             0x96AA
        SHADING_RATE_2X1_PIXELS_EXT                             0x96A8
        SHADING_RATE_2X2_PIXELS_EXT                             0x96A9
        SHADING_RATE_2X4_PIXELS_EXT                             0x96AD
        SHADING_RATE_4X1_PIXELS_EXT                             0x96AB
        SHADING_RATE_4X2_PIXELS_EXT                             0x96AC
        SHADING_RATE_4X4_PIXELS_EXT                             0x96AE

    Accepted by the <combinerOp0> and <combinerOp1> parameters of
    ShadingRateCombinerOpsEXT:

        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT              0x96D2
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT           0x96D3
        FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT               0x96D4
        FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT               0x96D5
        FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT               0x96D6

    Accepted by the <pname> parameter of GetIntegerv, GetBooleanv, GetFloatv,
    and GetInteger64v:

        SHADING_RATE_EXT                                                         0x96D0
        MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT                     0x96D7
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT                     0x96D8
        MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT                    0x96D9
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT                    0x96DA
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT              0x96DB
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT                          0x96DC
        FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT     0x96DD
        FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT                     0x96DE
        FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT  0x96DF
        FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT                0x8F6F
        FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_MULTI_VIEWPORT_SUPPORTED_EXT   0x9780


Modifications to the OpenGL 4.6 Specification (Core Profile)

    Modify Section 8.14.1, Scale Factor and Level-of-Detail, p. 256

    (modify the function approximating Scale Factor (P) to allow implementations
    to scale implicit derivatives based on the shading rate. The scale occurs
    before the LOD bias and before LOD clamping)

    Modify the definitions of (mu, mv, mw):

                  |   du       du    |
        mu = max  |  -----  , -----  |
                  |   dx       dy    |

                  |   dv       dv    |
        mv = max  |  -----  , -----  |
                  |   dx       dy    |

                  |   dw       dw    |
        mw = max  |  -----  , -----  |
                  |   dx       dy    |
    to:
                  |   du          du        |
        mu = max  |  ---- * sx , ---- * sy  |
                  |   dx          dy        |

                  |   dv          dv        |
        mv = max  |  ---- * sx , ---- * sy  |
                  |   dx          dy        |

                  |   dw          dw        |
        mw = max  |  ---- * sx , ---- * sy  |
                  |   dx          dy        |

        where (sx, sy) refer to _effective shading rate_ (w', h') specified in
        section 14.X.4.


    Modify Section 9.2.3, Framebuffer Object Queries, p. 307

    (modify the description of GetFramebufferAttachmentParameteriv and
    GetNamedFramebufferAttachmentParameteriv to include
    SHADING_RATE_ATTACHMENT_EXT)

    Otherwise, attachment must be one of the attachment points of the
    framebuffer listed in table 9.1 or SHADING_RATE_ATTACHMENT_EXT.


    Modify Section 9.4.1, Framebuffer Attachment Completeness, p. 328

    (add the following to the list of conditions required for framebuffer
    attachment)

    If <image> is a two-dimensional array and the attachment is
    SHADING_RATE_ATTACHMENT_EXT, all the selected layers,
    [<baseLayer>, <baseLayer> + <numLayers>), are each less than the layer
    count of the texture.


    Modify Section 14.3.1, Multisampling, p. 466

    (add to the end of the section)

    When the _effective shading rate_ (Section 14.X) is set to a value other
    than SHADING_RATE_1X1_PIXELS_EXT, the rasterization will occur at a
    specified _shading rate_ and will result in fragments covering a <W>x<H>
    group of pixels.

    When multisample rasterization is enabled, the samples of the fragment
    will consist of the samples for each of the pixels in the group. The
    fragment center will be the center of this group of pixels. Each fragment
    will include a coverage value with (W * H * SAMPLES) bits. For example, if
    SHADING_RATE_EXT is 2x2 and the currently bound framebuffer object has
    SAMPLES equal to 4 (4xMSAA), then the fragment will consist of 4 pixels
    and 16 samples. Similarly, each fragment will have (W * H * SAMPLES) depth
    values and associated data.


Add new section 14.X before Section 14.4, Points, p. 468

    Section 14.X, Fragment Shading Rate

    By default, each fragment processed by programmable fragment processing
    corresponds to a single pixel with a single (x,y) coordinate. When using
    multisampling, implementations are permitted to run separate fragment
    shader invocations for each sample, but often only run a single invocation
    for all samples of the fragment. We will refer to the density of fragment
    shader invocations as the _shading rate_.

    Applications can use the shading rate to increase the size of fragments to
    cover multiple pixels and reduce the amount of fragment shader work.
    Applications can also use the shading rate to explicitly control the
    minimum number of fragment shader invocations when multisampling.

    Section 14.X.1, Draw Call Fragment Shading Rate

    The draw call fragment shading rate can be controlled with the command

        void ShadingRateEXT(enum rate);

    <rate> specifies the value of SHADING_RATE_EXT, and defines the
    _shading rate_. Valid values for <rate> are described in table X.1.

        Shading Rate                   Size
        ----------------------------   -----
        SHADING_RATE_1X1_PIXELS_EXT     1x1
        SHADING_RATE_1X2_PIXELS_EXT     1x2
        SHADING_RATE_1X4_PIXELS_EXT     1x4
        SHADING_RATE_2X1_PIXELS_EXT     2x1
        SHADING_RATE_2X2_PIXELS_EXT     2x2
        SHADING_RATE_2X4_PIXELS_EXT     2x4
        SHADING_RATE_4X1_PIXELS_EXT     4x1
        SHADING_RATE_4X2_PIXELS_EXT     4x2
        SHADING_RATE_4X4_PIXELS_EXT     4x4

        Table X.1:  Shading rates accepted by ShadingRateEXT. An entry of
        "<W>x<H>" in the "Size" column indicates that the shading rate requests
        fragments with a width and height (in pixels) of <W> and <H>,
        respectively.

    If the shading rate is specified with ShadingRateEXT, it will apply to all
    draw buffers. If the shading rate has not been set, the shading rate will
    be SHADING_RATE_1X1_PIXELS_EXT. In either case, the shading rate will be
    further adjusted as described in the following sections.

    Errors

        INVALID_ENUM is generated by ShadingRateEXT if <rate> is not a valid
        shading rate from table X.1.


[[If GL_EXT_fragment_shading_rate_primitive is supported]]
    Section 14.X.2, Primitive Fragment Shading Rate

    The primitive fragment shading rate can be set via the built-in output
    variable gl_PrimitiveShadingRateEXT in the last active pre-rasterization
    shader stage. The rate associated with a given primitive is sourced from
    the value written to gl_PrimitiveShadingRateEXT by that primitive’s
    provoking vertex. If the last active pre-rasterization shader stage does
    not write to gl_PrimitiveShadingRateEXT, then it is as if the shader
    specified a fragment shading rate value of 0, indicating a horizontal and
    vertical rate of 1 pixel.

    FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_MULTI_VIEWPORT_SUPPORTED_EXT
    specifies whether the primitive fragment shading rate can be used when
    multiple viewports are used. If this value is FALSE, only a single viewport
    must be used, and applications must not write to the gl_ViewportIndex
    built-in when setting gl_PrimitiveShadingRateEXT.


[[If GL_EXT_fragment_shading_rate_attachment is supported]]
    Section 14.X.3, Attachment Fragment Shading Rate

    An attachment shading rate can be set by attaching a specified image from
    a texture object as one of the logical buffers of a framebuffer object
    with the command:

    void FramebufferShadingRateEXT(enum target, enum attachment, uint texture,
                                   GLint baseLayer, GLsizei numLayers,
                                   GLsizei texelWidth, GLsizei texelHeight);

    <target> must be DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or FRAMEBUFFER.
    FRAMEBUFFER is equivalent to DRAW_FRAMEBUFFER. <attachment> must be
    SHADING_RATE_ATTACHMENT_EXT.

    If <texture> is not zero, then <texture> must name an existing
    immutable-format texture with a target of TEXTURE_2D or TEXTURE_2D_ARRAY
    with a format of R8UI. If <texture> has multiple mipmap levels, only the
    base level will be used as the fragment shading rate attachment.

    <baseLayer> specifies the base layer of a two-dimensional image within
    <texture>. <numLayers> specifies the number of layers, starting from
    <baseLayer> from within <texture> to attach.

    <texelWidth> and <texelHeight> specify the width and height of the
    framebuffer region corresponding to each texel in a fragment shading rate
    attachment. Both parameters must be power-of-two values within the
    implementation-defined ranges:

    * <texelWidth> must be in the range
      [MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT,
       MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT]

    * <texelHeight> must be in the range
      [MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT,
       MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT]

    These implementation limits define the supported range for the framebuffer
    portion size corresponding to each texel in a fragment shading rate
    attachment. All limit values are guaranteed to be power-of-two, minimum
    values must be less than or equal to maximum values.

    Each pixel in the framebuffer is assigned an attachment fragment shading
    rate by the corresponding texel in the fragment shading rate attachment,
    according to:

        x' = floor(x / region_x)
        y' = floor(y / region_y)

    where x' and y' are the coordinates of a texel in the fragment shading
    rate attachment, x and y are the coordinates of the pixel in the
    framebuffer, and region_x and region_y are the size of the region each
    texel corresponds to, as defined by the <texelWidth> and <texelHeight>
    parameters to FramebufferShadingRateEXT.

    If both the shading rate attachment and the framebuffer have multiple
    layers, the shading rate attachment texel is selected from the layer
    determined by the built-in variable gl_Layer. Otherwise, the texel is
    unconditionally selected from the first layer of the attachment.

    The fragment size is encoded into the first component of the identified
    texel as follows:

        size_w = 2^((texel/4)&3)
        size_h = 2^(texel&3)

    where texel is the value in the first component of the identified texel,
    and size_w and size_h are the width and height of the fragment size,
    decoded from the texel. If no fragment shading rate attachment is
    specified, this size is calculated as size_w = size_h = 1. Applications
    must not specify a width or height greater than 4 by this method.

    The built-in input variable gl_ShadingRateEXT adheres to the above encoding.

    Errors

        An INVALID_ENUM error is generated if <target> is not
        DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or FRAMEBUFFER.

        An INVALID_ENUM error is generated if <attachment> is not
        SHADING_RATE_ATTACHMENT_EXT.

        An INVALID_VALUE error is generated if <texture> is not zero and is
        not the name of an immutable texture object.

        An INVALID_VALUE error is generated if <baseLayer> is greater than or
        equal to the value of MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT.

        An INVALID_VALUE error is generated if <numLayers> is greater than the
        value of MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT.

        An INVALID_VALUE error is generated if <texelWidth> / <texelHeight> is
        larger than
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT.

        An INVALID_VALUE error is generated if <texelHeight> / <texelWidth> is
        larger than
        MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT.

        An INVALID_OPERATION error is generated if the default framebuffer is
        bound to <target> and the value of
        FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT
        is FALSE.


    Section 14.X.4, Combining the Fragment Shading Rates

    The _effective shading rate_ is the final shading rate (Cxy') used for
    fragment invocations, which must be one of the rates returned by
    GetFragmentShadingRatesEXT for the sample count used by rasterization.

    If any of the following conditions are met, Cxy' must be set to
    SHADING_RATE_1X1_PIXELS_EXT:

        * Per-sample shading is enabled.

        * The fragment shader statically writes to the built-in variable
          gl_FragDepth and the value of
          FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT
          is FALSE.

        * The value of FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT is
          FALSE and either the value of SAMPLE_MASK_VALUE does not have all
          bits of all words set, or the fragment shader statically writes to
          the built-in variable gl_SampleMask.

        * The fragment shader statically references the built-in variable
          gl_FragCoord and does not enable the GL_EXT_fragment_shading_rate
          extension.

    Otherwise, each of the specified shading rates are combined and then used
    to derive the value of Cxy'. As there are three ways to specify shading
    rates, two combiner operations are specified - between the pipeline and
    primitive shading rates, and between the result of that and the attachment
    shading rate.

    The fragment shading rate combiner operations are controlled with the command

        void ShadingRateCombinerOpsEXT(enum combinerOp0, enum combinerOp1);

    <combinerOp0> and <combinerOp1> must be one of the combiner operations
    listed in table X.2.

        Combiner Operation                               Result of combine(Axy,Bxy)
        ---------------------------------------------    --------------------------
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT       Axy
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT    Bxy
        FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT        min(Axy,Bxy)
        FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT        max(Axy,Bxy)
        FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT        Axy*Bxy

        Table X.2:  Combiner operations accepted by ShadingRateCombinerOpsEXT.
        Where combine(Axy,Bxy) is the combine operation, Axy and Bxy are the
        inputs to the operation.

    The FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT,
    FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT, and
    FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT combiner operations are only
    supported if the value of
    FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT is TRUE.

    These operations are performed in a component-wise fashion.

    This is used to generate a combined fragment area using the equation:

        Cxy = combine(Axy,Bxy)

    where Cxy is the combined fragment area result, Axy and Bxy are the
    fragment areas of the fragment shading rates being combined.

    Two combine operations are performed, first with Axy equal to the draw
    call fragment shading rate and Bxy equal to the primitive fragment shading
    rate, with the combine() operation selected by <combinerOp0>. A second
    combination is then performed, with Axy equal to the result of the first
    combination and Bxy equal to the attachment fragment shading rate, with
    the combine() operation selected by <combinerOp1>. The result of the
    second combination is used as the final fragment shading rate, reported
    via the built-in input variable gl_ShadingRateEXT. Implementations may
    clamp the Cxy result of each combiner operation separately, or only after
    the second combiner operation.

    A fragment shading rate Rxy representing any of Axy, Bxy or Cxy is clamped
    as follows. If Rxy is one of the rates returned by GetFragmentShadingRatesEXT
    for the sample count used by rasterization, the clamped shading rate Rxy' is
    Rxy. Otherwise, Rxy' is selected from the rates returned by
    GetFragmentShadingRatesEXT for the sample count used by rasterization. From
    this list of supported rates, the following steps are applied in order, to
    select a single value:

    1. Keep only rates where Rx' ≤ Rx and Ry' ≤ Ry.
        * Implementations may also keep rates where Rx' ≤ Ry and Ry' ≤ Rx.

    2. Keep only rates with the highest area (Rx' × Ry').

    3. Keep only rates with the lowest aspect ratio (Rx' + Ry').

    4. In cases where a wide (e.g. 4x1) and tall (e.g. 1x4) rate remain, the
       implementation may choose either rate. However, it must choose this
       rate consistently for the same shading rates and combiner operations
       for the lifetime of the GL context.

    Errors

        An INVALID_ENUM error is generated if <combinerOp0> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT, or
        FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT

        An INVALID_ENUM error is generated if <combinerOp1> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT,
        FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT, or
        FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT

        An INVALID_OPERATION error is generated if
        the value of
        FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT
        is FALSE and <combinerOp0> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT or
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT

        An INVALID_OPERATION error is generated if
        the value of
        FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT
        is FALSE and <combinerOp1> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT or
        FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT

[[If GL_EXT_fragment_shading_rate_primitive is not supported]]
        An INVALID_OPERATION error is generated if <combinerOp0> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT

[[If GL_EXT_fragment_shading_rate_attachment is not supported]]
        An INVALID_OPERATION error is generated if <combinerOp1> is not
        FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT


    Section 14.X.5, Fragment Shading Rate Queries

    The supported fragment shading rates can be queried with the command

        void GetFragmentShadingRatesEXT(sizei samples, sizei maxCount,
                                        sizei *count, enum *shadingRates);

    <samples> specifies the sample count for which supported shading rates
    are being queried. The supported shading rates for <samples> will be
    written in <shadingRates>, and must be the rates specified in table X.1.
    The maximum number of rates that may be written into <shadingRates> is
    specified by <maxCount>. The actual number of rates written into
    <shadingRates> is returned in <count>. If no rates are supported, <count>
    is set to zero. If <count> is NULL then it is ignored.

    Implementations must support at least the shading rates listed in Table
    X.3. Additional shading rates may be supported and will be included in
    the returned list.

            <samples>     |   Required Shading Rates
            --------------|--------------------------------
            1             |   SHADING_RATE_1X1_PIXELS_EXT,
                          |   SHADING_RATE_1X2_PIXELS_EXT,
                          |   SHADING_RATE_2X1_PIXELS_EXT,
                          |   SHADING_RATE_2X2_PIXELS_EXT
            --------------|--------------------------------
            4             |   SHADING_RATE_1X1_PIXELS_EXT,
                          |   SHADING_RATE_1X2_PIXELS_EXT,
                          |   SHADING_RATE_2X1_PIXELS_EXT,
                          |   SHADING_RATE_2X2_PIXELS_EXT
            -----------------------------------------------

            Table X.3:  Minimum required shading rates by sample count.
            Implementations may support additional rates beyond these
            minimum requirements.

    Errors

        An INVALID_VALUE error is generated if <maxCount> is negative.


    Modifications to Section 14.9.2, Scissor Test, p. 484

    (add to the end of the section)

    When the _effective shading rate_ results in fragments covering more than
    one pixel, the scissor tests are performed separately for each pixel in
    the fragment. If a pixel covered by a fragment fails the scissor test,
    that pixel is treated as though it was not covered by the primitive. If
    all pixels covered by a fragment are either not covered by the primitive
    being rasterized or fail the scissor test, the fragment is discarded.


    Modifications to Section 14.9.3, Multisample Fragment Operations, p. 486

    (modify the last sentence of the first paragraph to indicate that
    sample mask operations are performed when shading rate is used, even if
    multisampling is not enabled, which can produce fragments covering more
    than one pixel where each pixel is considered a "sample")

    ... this step is skipped unless the _effective shading rate_ results in a
    value other than SHADING_RATE_1X1_PIXELS_EXT.

    (add to the end of the section)

    When the _effective shading rate_ results in fragments covering more than
    one pixel, each fragment will generate a composite coverage mask that
    includes separate coverage bits for each sample in each pixel covered by
    the fragment. This composite coverage mask will be used by the GLSL
    built-in input variable gl_SampleMaskIn[] and updated according to the
    built-in output variable gl_SampleMask[]. The number of composite coverage
    mask bits in the built-in variables and their mapping to a specific pixel
    and sample number within that pixel is implementation-defined.


    Modify Section 15.1, Fragment Shader Variables, p. 488

    (modify sixth paragraph, p. 489, specifying that the "centroid" location
    for multi-pixel fragments is implementation-dependent, and is allowed to
    be outside the primitive)

    ... When interpolating variables declared using "centroid in", the
    variable is sampled at a location within the pixel covered by the
    primitive generating the fragment. When the _effective shading rate_
    results in fragments covering more than one pixel, variables declared
    using "centroid in" are sampled from an implementation-dependent location
    within any one of the covered pixels. ...


    Modify Section 17.3, Per-Fragment Operations, p. 501

    (insert a new paragraph after the first paragraph of the section)

    When the _effective shading rate_ results in fragments covering multiple
    pixels, the operations described in the section are performed independently
    for each pixel covered by the fragment. The set of samples covered by each
    pixel is determined by extracting the portion of the fragment's composite
    coverage that applies to that pixel, as described in section 14.9.3.


Interactions with OpenGL ES 3.2

    If implemented in OpenGL ES, references to multiple viewports and
    FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_MULTI_VIEWPORT_SUPPORTED_EXT
    should be removed.

Interactions with OVR_multiview

    If OVR_multiview is supported, SHADING_RATE_EXT applies to all views.

    If multiview is enabled and the shading rate attachment has multiple
    layers, the shading rate attachment texel is selected from the layer
    determined by the gl_ViewID_OVR built-in.

Interactions with QCOM_framebuffer_foveated and QCOM_texture_foveated

    QCOM_framebuffer_foveated and QCOM_texture_foveated specify a pixel
    density which is exposed as a fragment size via the fragment
    shader built-in gl_FragSizeEXT. This extension defines an effective
    shading rate which is exposed to fragment shaders via the shader
    built-in gl_ShadingRateEXT. If either foveation extension is enabled in
    conjunction with this extension, then the values of the gl_FragSizeEXT
    and gl_ShadingRateEXT built-ins will be the component-wise product of
    both fragment sizes.

Interactions with GL_EXT_fragment_invocation_density

    If the shader enables GL_EXT_fragment_invocation_density in combination
    with this extension, then the gl_FragSizeEXT and gl_FragInvocationCountEXT
    built-in variables contain the fragment size and the number of invocations,
    respectively, based on the effective fragment shading rate.

Interactions with GL_EXT_shader_pixel_local_storage and
GL_EXT_shader_pixel_local_storage2

    Pixel local storage is not supported in combination with shading rates
    other than SHADING_RATE_1X1_PIXELS_EXT. Attempting to enable pixel local
    storage while the currently bound framebuffer object has a non-zero value
    of SHADING_RATE_ATTACHMENT_EXT will generate an INVALID_OPERATION error.
    Attempting to enable pixel local storage while the current value of
    SHADING_RATE_EXT is not SHADING_RATE_1X1_PIXELS_EXT will generate an
    INVALID_OPERATION error. If pixel local storage is enabled, an
    INVALID_OPERATION error will be generated by ShadingRateEXT if <rate> is
    not SHADING_RATE_1X1_PIXELS_EXT.

    [[If GL_EXT_fragment_shading_rate_primitive is supported]]
    A program will fail to link if a per primitive shading rate is specified
    in a vertex or geometry shader while the fragment shader statically reads
    or writes to a pixel local storage variable.

Interactions with GL_EXT_shader_framebuffer_fetch and
GL_EXT_shader_framebuffer_fetch_non_coherent

    When the value of SAMPLE_BUFFERS is 0, gl_LastFragData[] is populated with
    the value last written to one of the pixels to which the current fragment
    is destined, chosen in an implementation-dependent manner.

    When the value of SAMPLE_BUFFERS is 1 and the current framebuffer color is
    accessed in the fragment shader, the fragment shader will be invoked
    separately for each covered sample. Since this is equivalent to per-sample
    shading, the fragment shading rate will be set to SHADING_RATE_1X1_PIXELS_EXT
    in this case.

Interactions with GL_ARM_shader_framebuffer_fetch and
GL_ARM_shader_framebuffer_fetch_depth_stencil

    If FETCH_PER_SAMPLE_ARM is enabled, the fragment shading rate is set to
    SHADING_RATE_1X1_PIXELS_EXT. Otherwise, the values of gl_LastFragColorARM,
    gl_LastFragDepthARM and gl_LastFragStencilARM are the color, depth, or
    stencil values, respectively, and are an implementation-dependent
    combination of the values of the pixels to which the current fragment is
    destined. If the current render target is multisampled, the values are an
    implementation-dependent combination of the samples covered by the fragment.

Errors

    See the "Errors" sections for individual commands above.

New State

Add to table 23.9, Rasterization

    Get Value          Type   Get Command   Initial Value                 Description              Sec
    ---------          ----   -----------   -------------                 -----------              ---
    SHADING_RATE_EXT   E      GetIntegerv   SHADING_RATE_1X1_PIXELS_EXT   Draw call shading rate   14.X.1

New Implementation Dependent State

Add to table 23.53, Implementation Dependent Values

    Get Value                                                   Type  Get Command  Minimum Value  Description                         Sec
    ---------                                                   ----  -----------  -------------  -----------                         ---
    FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_-           B     GetBooleanv  -              Support for writing FragDepth from  14.X.4
    WRITES_SUPPORTED_EXT                                                                          a fragment shader for multi-pixel
                                                                                                  fragments
    FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT        B     GetBooleanv  -              Support for sample masks with       14.X.4
                                                                                                  multi-pixel fragments
    FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT   B     GetBooleanv  -              Support for non-trivial combiners   14.X.4

[[If GL_EXT_fragment_shading_rate_primitive is supported]]
    FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_-                 B     GetBooleanv  -              Support for applying primitive      14.X.2
    MULTI_VIEWPORT_SUPPORTED_EXT                                                                  shading rate on multiple viewports

[[If GL_EXT_fragment_shading_rate_attachment is supported]]
    MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT        Z+    GetIntegerv  32 (**)        minimum supported width of the      14.X.3
                                                                                                  portion of the framebuffer
                                                                                                  corresponding to each texel in
                                                                                                  a fragment shading rate attachment
    MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT       Z+    GetIntegerv  32 (**)        minimum supported height of the     14.X.3
                                                                                                  portion of the framebuffer
                                                                                                  corresponding to each texel in
                                                                                                  a fragment shading rate attachment
    MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT        Z+    GetIntegerv  8              maximum supported width of the      14.X.3
                                                                                                  portion of the framebuffer
                                                                                                  corresponding to each texel in
                                                                                                  a fragment shading rate attachment
    MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT       Z+    GetIntegerv  8              maximum supported height of the     14.X.3
                                                                                                  portion of the framebuffer
                                                                                                  corresponding to each texel in
                                                                                                  a fragment shading rate attachment
    MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT Z+    GetIntegerv  1              maximum aspect ratio between the    14.X.3
                                                                                                  width and height of the portion of
                                                                                                  the framebuffer corresponding to
                                                                                                  each texel in a fragment shading
                                                                                                  rate attachment
    MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT             Z+    GetIntegerv  1              maximum number of layers in a
                                                                                                  fragment shading rate attachment    14.X.3
    FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_-                     B     GetBooleanv  -              support for attachment shading      14.X.3
    DEFAULT_FRAMEBUFFER_SUPPORTED_EXT                                                             rates on the default framebuffer

(**) The value of MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT is the maximum allowed, not the minimum
(**) The value of MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT is the maximum allowed, not the minimum

Issues

    (1) Do we need individual 'feature bits' for the draw call, primitive, and
        attachment shading rates?

    RESOLVED: Yes.

    This extension exposes different extension strings for these features:
    * GL_EXT_fragment_shading_rate is the baseline, and requires per draw call shading rates
    * GL_EXT_fragment_shading_rate_attachment adds support for shading rate attachments
    * GL_EXT_fragment_shading_rate_primitive adds support for per primitive shading rates

    (2) What optional parameters and options should we expose?

    RESOLVED: For reference, the Vulkan VK_KHR_fragment_shading_rate extension
    has the following properties:

    typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR {
        VkStructureType          sType;
        void*                    pNext;
        VkExtent2D               minFragmentShadingRateAttachmentTexelSize;
        VkExtent2D               maxFragmentShadingRateAttachmentTexelSize;
        uint32_t                 maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
        VkBool32                 primitiveFragmentShadingRateWithMultipleViewports;
        VkBool32                 layeredShadingRateAttachments;
        VkBool32                 fragmentShadingRateNonTrivialCombinerOps;
        VkExtent2D               maxFragmentSize;
        uint32_t                 maxFragmentSizeAspectRatio;
        uint32_t                 maxFragmentShadingRateCoverageSamples;
        VkSampleCountFlagBits    maxFragmentShadingRateRasterizationSamples;
        VkBool32                 fragmentShadingRateWithShaderDepthStencilWrites;
        VkBool32                 fragmentShadingRateWithSampleMask;
        VkBool32                 fragmentShadingRateWithShaderSampleMask;
        VkBool32                 fragmentShadingRateWithConservativeRasterization;
        VkBool32                 fragmentShadingRateWithFragmentShaderInterlock;
        VkBool32                 fragmentShadingRateWithCustomSampleLocations;
        VkBool32                 fragmentShadingRateStrictMultiplyCombiner;
    } VkPhysicalDeviceFragmentShadingRatePropertiesKHR;

    The mapping to this extension is as follows:

        minFragmentShadingRateAttachmentTexelSize              => MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT
                                                                  MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT
        maxFragmentShadingRateAttachmentTexelSize              => MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT
                                                                  MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT
        maxFragmentShadingRateAttachmentTexelSizeAspectRatio   => MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT
        primitiveFragmentShadingRateWithMultipleViewports      => [[OpenGL]] FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_MULTI_VIEWPORT_SUPPORTED_EXT
                                                               => [[OpenGL ES]] - (not supported; would be an interaction with GL_OES_viewport_array)
        layeredShadingRateAttachments                          => MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT
        fragmentShadingRateNonTrivialCombinerOps               => FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT
        maxFragmentSize                                        => - (not exposed as a limit; min requirements are stated in description of GetFragmentShadingRatesEXT)
        maxFragmentSizeAspectRatio                             => - (not exposed as a limit; min requirements are stated in description of GetFragmentShadingRatesEXT)
        maxFragmentShadingRateCoverageSamples                  => - (not exposed as a limit; min requirements are stated in description of GetFragmentShadingRatesEXT)
        maxFragmentShadingRateRasterizationSamples             => - (not exposed as a limit; min requirements are stated in description of GetFragmentShadingRatesEXT)
        fragmentShadingRateWithShaderDepthStencilWrites        => FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT
        fragmentShadingRateWithSampleMask                      => FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT
        fragmentShadingRateWithShaderSampleMask                => FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT
        fragmentShadingRateWithConservativeRasterization       => - (not supported; would be an interaction with GL_NV_conservative_raster and GL_INTEL_conservative_rasterization)
        fragmentShadingRateWithFragmentShaderInterlock         => - (not supported; would be an interaction with GL_NV_fragment_shader_interlock)
        fragmentShadingRateWithCustomSampleLocations           => - (not supported; would be an interaction with GL_NV_sample_locations)
        fragmentShadingRateStrictMultiplyCombiner              => - (implicitly required)

    (3) Should we add enumerants for 1x4 and 4x1 shading rates?

    RESOLVED: Yes, they are all included, but support is optional.

    (4) Should we have an equivalent to PRESERVE_SHADING_RATE_ASPECT_RATIO_QCOM
        from QCOM_shading_rate?

    RESOLVED: No. This extension follows the conventions of the
    VK_KHR_fragment_shading_rate extension, where the aspect ratios are
    constrained in a slightly different way than in QCOM_shading_rate.

    (5) Should the GLSL dependency be on GL_EXT_fragment_invocation_density or
        GLSL_EXT_fragment_shading_rate?

    RESOLVED: Primarily GL_EXT_fragment_shading_rate, but
    GL_EXT_fragment_invocation_density is also sufficient unless
    GL_EXT_fragment_shading_rate_primitive is used.

    (6) What is the interaction with QCOM_framebuffer_foveated and
        QCOM_texture_foveated?

    RESOLVED: See Interactions.

    (7) What fragment shading rates should be required?

    RESOLVED: The current draft matches the minimum requirements in other APIs
    (assuming 2xMSAA is not supported).

    (8) What are the interactions with GL_EXT_fragment_invocation_density?

    RESOLVED: If a shader declares that extension (and the implementation
    supports it), then the built-in variables defined by the extension
    will be filled with values representing the effective fragment shading
    rate.

    (9) How do we handle gl_FragCoord in the cases where the shader does not
        enable GL_EXT_fragment_shading_rate?

    RESOLVED: We fall back to a 1x1 shading rate.

    The implementation may need to calculate gl_FragCoord differently depending
    on the shading rate. But the shading rate is not known at shader
    compile-time. The implementation could add instructions to the shader
    to handle this, but that could affect performance in the general case
    - even when no shading rate is specified.

    A potential solution is to fall back to a 1x1 shading rate if the shader
    accesses gl_FragCoord unless GL_EXT_fragment_shading_rate is enabled.
    Enabling the extension acts as a hint that the shading rate will be
    specified at run-time.

    (10) How does this compare to GL_NV_shading_rate_image and
         GL_NV_primitive_shading_rate?

    RESOLVED: GL_NV_shading_rate_image and GL_NV_primitive_shading_rate offer
    similar functionality to this extension, but expose it in a slightly
    different way.

    Differences include:
    * This extension does not include the concept of a shader rate image
      palette. In the case where no shading image is bound,
      GL_NV_shading_rate_image uses the palette to provide a per draw-call
      rate. This extension sets the per-draw call rate separately.
    * GL_NV_shading_rate_image does not include rate combiners.
    * GL_NV_shading_rate_image does not allow the shading rates to be changed
      for the default framebuffer.
    * This extension binds the shading rate as a framebuffer attachment,
      GL_NV_shading_rate_image binds it directly to the state vector.

    (11) Should we include any functionality or restrictions from
         GL_NV_shading_rate_image?

    RESOLVED:

    * Interactions with ARB_fragment_shader_interlock are not included.
    * No equivalent of ShadingRateImageBarrierNV is included.
    * No equivalent of ShadingRateSampleOrderNV and
      ShadingRateSampleOrderCustomNV is included.
    * Restrictions on using fragment shading rate with the default framebuffer
      are included - by the DEFAULT_FRAMEBUFFER_SUPPORTED_EXT state.

    (12) Can we reuse the shading rate enumeration values from
         GL_QCOM_shading_rate?

    RESOLVED: Yes, since the semantics are identical.

Revision History

    Rev.    Date     Author    Changes
    ----  --------   --------  ----------------------------------------------
     1    2022-05-30 jhf       Initial EXT draft
     2    2022-07-07 jhf       Fixed typos in the spec text
     3    2024-07-03 jhf       Clarify Implementation Dependent Values table
     4    2025-10-09 jww       Add support for desktop OpenGL
