Name

    NV_blend_equation_advanced

Name Strings

    GL_NV_blend_equation_advanced
    GL_NV_blend_equation_advanced_coherent

Contact

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

Contributors

    Jeff Bolz, NVIDIA Corporation
    Mathias Heyer, NVIDIA Corporation
    Mark Kilgard, NVIDIA Corporation
    Daniel Koch, NVIDIA Corporation
    Rik Cabanier, Adobe

Status

    NV_blend_equation_advanced is released in NVIDIA Driver Release
    326.xx (June 2013).

Version

    Last Modified Date:         September 30, 2014
    NVIDIA Revision:            9

Number

    OpenGL Extension #433
    OpenGL ES Extension #163

Dependencies

    This extension is written against the OpenGL 4.1 Specification
    (Compatibility Profile).

    OpenGL 2.0 is required (for Desktop).

    OpenGL ES 2.0 is required (for mobile).

    EXT_blend_minmax is required (for mobile).

    This extension interacts with OpenGL 4.0.

    This extension interacts with OpenGL 4.1 (Core Profile).

    This extension interacts with OpenGL 4.3 or later.

    This extension interacts with OpenGL ES 2.0.

    This extension interacts with OpenGL ES 3.0.

    This extension interacts with NV_path_rendering.

Overview

    This extension adds a number of "advanced" blending equations that can be
    used to perform new color blending operations, many of which are more
    complex than the standard blend modes provided by unextended OpenGL.  This
    extension provides two different extension string entries:

    - NV_blend_equation_advanced:  Provides the new blending equations, but
      guarantees defined results only if each sample is touched no more than
      once in any single rendering pass.  The command BlendBarrierNV() is
      provided to indicate a boundary between passes.

    - NV_blend_equation_advanced_coherent:  Provides the new blending
      equations, and guarantees that blending is done coherently and in API
      primitive ordering.  An enable is provided to allow implementations to
      opt out of fully coherent blending and instead behave as though only
      NV_blend_equation_advanced were supported.

    Some implementations may support NV_blend_equation_advanced without
    supporting NV_blend_equation_advanced_coherent.

    In unextended OpenGL, the set of blending equations is limited, and can be
    expressed very simply.  The MIN and MAX blend equations simply compute
    component-wise minimums or maximums of source and destination color
    components.  The FUNC_ADD, FUNC_SUBTRACT, and FUNC_REVERSE_SUBTRACT
    multiply the source and destination colors by source and destination
    factors and either add the two products together or subtract one from the
    other.  This limited set of operations supports many common blending
    operations but precludes the use of more sophisticated transparency and
    blending operations commonly available in many dedicated imaging APIs.

    This extension provides a number of new "advanced" blending equations.
    Unlike traditional blending operations using the FUNC_ADD equation, these
    blending equations do not use source and destination factors specified by
    BlendFunc.  Instead, each blend equation specifies a complete equation
    based on the source and destination colors.  These new blend equations are
    used for both RGB and alpha components; they may not be used to perform
    separate RGB and alpha blending (via functions like
    BlendEquationSeparate).

    These blending operations are performed using premultiplied colors, where
    RGB colors stored in the framebuffer are considered to be multiplied by
    alpha (coverage).  The fragment color may be considered premultiplied or
    non-premultiplied, according the BLEND_PREMULTIPLIED_SRC_NV blending
    parameter (as specified by the new BlendParameteriNV function).  If
    fragment color is considered non-premultiplied, the (R,G,B) color
    components are multiplied by the alpha component prior to blending.  For
    non-premultiplied color components in the range [0,1], the corresponding
    premultiplied color component would have values in the range [0*A,1*A].

    Many of these advanced blending equations are formulated where the result
    of blending source and destination colors with partial coverage have three
    separate contributions:  from the portions covered by both the source and
    the destination, from the portion covered only by the source, and from the
    portion covered only by the destination.  The blend parameter
    BLEND_OVERLAP_NV can be used to specify a correlation between source and
    destination pixel coverage.  If set to CONJOINT_NV, the source and
    destination are considered to have maximal overlap, as would be the case
    if drawing two objects on top of each other.  If set to DISJOINT_NV, the
    source and destination are considered to have minimal overlap, as would be
    the case when rendering a complex polygon tessellated into individual
    non-intersecting triangles.  If set to UNCORRELATED_NV (default), the
    source and destination coverage are assumed to have no spatial correlation
    within the pixel.

    In addition to the coherency issues on implementations not supporting
    NV_blend_equation_advanced_coherent, this extension has several
    limitations worth noting.  First, the new blend equations are not
    supported while rendering to more than one color buffer at once; an
    INVALID_OPERATION will be generated if an application attempts to render
    any primitives in this unsupported configuration.  Additionally, blending
    precision may be limited to 16-bit floating-point, which could result in a
    loss of precision and dynamic range for framebuffer formats with 32-bit
    floating-point components, and in a loss of precision for formats with 12-
    and 16-bit signed or unsigned normalized integer components.

New Procedures and Functions

    void BlendParameteriNV(enum pname, int value);
    void BlendBarrierNV(void);

New Tokens

    Accepted by the <cap> parameter of Disable, Enable, and IsEnabled, and by
    the <pname> parameter of GetIntegerv, GetBooleanv, GetFloatv, GetDoublev
    and GetInteger64v:

        BLEND_ADVANCED_COHERENT_NV                      0x9285

    Note:  The BLEND_ADVANCED_COHERENT_NV enable is provided if and only if
    the NV_blend_equation_advanced_coherent extension is supported.  On
    implementations supporting only NV_blend_equation_advanced, this enable is
    considered not to exist.

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

        BLEND_PREMULTIPLIED_SRC_NV                      0x9280
        BLEND_OVERLAP_NV                                0x9281

    Accepted by the <value> parameter of BlendParameteriNV when <pname> is
    BLEND_PREMULTIPLIED_SRC_NV:

        TRUE
        FALSE

    Accepted by the <value> parameter of BlendParameteriNV when <pname> is
    BLEND_OVERLAP_NV:

        UNCORRELATED_NV                                 0x9282
        DISJOINT_NV                                     0x9283
        CONJOINT_NV                                     0x9284

    Accepted by the <mode> parameter of BlendEquation and BlendEquationi:

        ZERO                                            // reused from core
        SRC_NV                                          0x9286
        DST_NV                                          0x9287
        SRC_OVER_NV                                     0x9288
        DST_OVER_NV                                     0x9289
        SRC_IN_NV                                       0x928A
        DST_IN_NV                                       0x928B
        SRC_OUT_NV                                      0x928C
        DST_OUT_NV                                      0x928D
        SRC_ATOP_NV                                     0x928E
        DST_ATOP_NV                                     0x928F
        XOR_NV                                          0x1506
        MULTIPLY_NV                                     0x9294
        SCREEN_NV                                       0x9295
        OVERLAY_NV                                      0x9296
        DARKEN_NV                                       0x9297
        LIGHTEN_NV                                      0x9298
        COLORDODGE_NV                                   0x9299
        COLORBURN_NV                                    0x929A
        HARDLIGHT_NV                                    0x929B
        SOFTLIGHT_NV                                    0x929C
        DIFFERENCE_NV                                   0x929E
        EXCLUSION_NV                                    0x92A0
        INVERT                                          // reused from core
        INVERT_RGB_NV                                   0x92A3
        LINEARDODGE_NV                                  0x92A4
        LINEARBURN_NV                                   0x92A5
        VIVIDLIGHT_NV                                   0x92A6
        LINEARLIGHT_NV                                  0x92A7
        PINLIGHT_NV                                     0x92A8
        HARDMIX_NV                                      0x92A9

        HSL_HUE_NV                                      0x92AD
        HSL_SATURATION_NV                               0x92AE
        HSL_COLOR_NV                                    0x92AF
        HSL_LUMINOSITY_NV                               0x92B0

        PLUS_NV                                         0x9291
        PLUS_CLAMPED_NV                                 0x92B1
        PLUS_CLAMPED_ALPHA_NV                           0x92B2
        PLUS_DARKER_NV                                  0x9292
        MINUS_NV                                        0x929F
        MINUS_CLAMPED_NV                                0x92B3
        CONTRAST_NV                                     0x92A1
        INVERT_OVG_NV                                   0x92B4
        RED_NV                                          0x1903
        GREEN_NV                                        0x1904
        BLUE_NV                                         0x1905

    NOTE:  These enums are not accepted by the <modeRGB> or <modeAlpha>
    parameters of BlendEquationSeparate or BlendEquationSeparatei.

    NOTE:  The tokens XOR_NV, RED_NV, GREEN_NV, and BLUE_NV have the same
    values as core OpenGL API enumerants with names without the "_NV"
    suffixes.  Either #define can be used, but the non-suffixed #defines are
    not available in OpenGL ES 2.0 and XOR is not available in OpenGL ES 3.0.

Additions to Chapter 2 of the OpenGL 4.1 Specification (OpenGL Operation)

    None.

Additions to Chapter 3 of the OpenGL 4.1 Specification (Rasterization)

    None.

Additions to Chapter 4 of the OpenGL 4.1 Specification (Per-Fragment
Operations and the Frame Buffer)

    Modify Section 4.1.8, Blending (p. 359).

    (modify the first paragraph, p. 361, allowing for new values in the
    <mode> parameter) ... <modeRGB> and <modeAlpha> must be one of
    FUNC_ADD, FUNC_SUBTRACT, FUNC_REVERSE_SUBTRACT, MIN, or MAX as listed
    in Table 4.1.  <mode> must be one of the values in Table 4.1,
    or one of the blend equations listed in tables X.2, X.3, and X.4. ...

    (modify the third paragraph, p. 361, specifying minimum precision and
    dynamic range for blend operations) ... Blending computations are treated
    as if carried out in floating-point.  For the equations in table 4.1,
    blending computations will be performed with a precision and dynamic range
    no lower than that used to represent destination components.  For the
    equations in table X.2, X.3, and X.4, blending computations will be
    performed with a precision and dynamic range no lower than the smaller of
    that used to represent destination components or that used to represent
    16-bit floating-point values as described in section 2.1.1.

    (add unnumbered subsection prior to "Dual Source Blending and Multiple
     Draw Buffers", p. 363)

    Advanced Blend Equations

    The advanced blend equations are those listed in tables X.2, X.3, and X.4.
    Parameters related to the advanced blend equations can be set by calling

      void BlendParameteriNV(enum pname, int param);

    with <pname> set to BLEND_PREMULTIPLIED_SRC_NV or BLEND_OVERLAP_NV.  When
    <pname> is BLEND_PREMULTIPLIED_SRC_NV, the valid values for <param> are
    TRUE or FALSE.  When <pname> is BLEND_OVERLAP_NV, the valid values for
    <param> are UNCORRELATED_NV, CONJOINT_NV, and DISJOINT_NV.  An
    INVALID_ENUM error is generated if <pname> is not
    BLEND_PREMULTIPLIED_SRC_NV or BLEND_OVERLAP_NV, or if <param> is not a
    legal value for <pname>.

    When using one of the equations in table X.2 or X.3, blending is performed
    according to the following equations:

      R = f(Rs',Rd')*p0(As,Ad) + Y*Rs'*p1(As,Ad) + Z*Rd'*p2(As,Ad)
      G = f(Gs',Gd')*p0(As,Ad) + Y*Gs'*p1(As,Ad) + Z*Gd'*p2(As,Ad)
      B = f(Bs',Bd')*p0(As,Ad) + Y*Bs'*p1(As,Ad) + Z*Bd'*p2(As,Ad)
      A =          X*p0(As,Ad) +     Y*p1(As,Ad) +     Z*p2(As,Ad)

    where the function f and terms X, Y, and Z are specified in the table.
    The R, G, and B components of the source color used for blending are
    derived according to the premultiplied source color blending parameter,
    which is set by calling BlendParameteriNV with <pname> set to 
    BLEND_PREMULTIPLIED_SRC_NV, and <param> set to TRUE or FALSE.
    If the parameter is set to TRUE, the fragment color components are
    considered to have been premultiplied by the A component prior to
    blending.  The base source color (Rs',Gs',Bs') is obtained by dividing
    through by the A component:

      (Rs', Gs', Bs') =
        (0, 0, 0),              if As == 0
        (Rs/As, Gs/As, Bs/As),  otherwise

    If the premultiplied source color parameter is FALSE, the fragment color
    components are used as the base color:

      (Rs', Gs', Bs') = (Rs, Gs, Bs)

    The destination color components are always considered to have been
    premultiplied by the destination A component and the base destination
    color (Rd', Gd', Bd') is obtained by dividing through by the A component:

      (Rd', Gd', Bd') =
        (0, 0, 0),               if Ad == 0
        (Rd/Ad, Gd/Ad, Bd/Ad),   otherwise

    When blending using advanced blend equations, we expect that the R, G, and
    B components of premultiplied source and destination color inputs be
    stored as the product of non-premultiplied R, G, and B component values
    and the A component of the color.  If any R, G, or B component of a
    premultiplied input color is non-zero and the A component is zero, the
    color is considered ill-formed, and the corresponding component of the
    blend result will be undefined.

    The weighting functions p0, p1, and p2 are defined in table X.1.  In these
    functions, the A components of the source and destination colors are taken
    to indicate the portion of the pixel covered by the fragment (source) and
    the fragments previously accumulated in the pixel (destination).  The
    functions p0, p1, and p2 approximate the relative portion of the pixel
    covered by the intersection of the source and destination, covered only by
    the source, and covered only by the destination, respectively.  These
    functions are specified by the blend overlap parameter, which can be set
    by calling BlendParameteriNV with <pname> set to BLEND_OVERLAP_NV.  <param>
    can be one of UNCORRELATED_NV (default), CONJOINT_NV, and DISJOINT_NV.
    UNCORRELATED_NV indicates that there is no correlation between the source
    and destination coverage.  CONJOINT_NV and DISJOINT_NV indicate that the
    source and destination coverage are considered to have maximal or minimal
    overlap, respectively.

      Overlap Mode              Weighting Equations
      ---------------           --------------------------
      UNCORRELATED_NV           p0(As,Ad) = As*Ad
                                p1(As,Ad) = As*(1-Ad)
                                p2(As,Ad) = Ad*(1-As)
      CONJOINT_NV               p0(As,Ad) = min(As,Ad)
                                p1(As,Ad) = max(As-Ad,0)
                                p2(As,Ad) = max(Ad-As,0)
      DISJOINT_NV               p0(As,Ad) = max(As+Ad-1,0)
                                p1(As,Ad) = min(As,1-Ad)
                                p2(As,Ad) = min(Ad,1-As)

      Table X.1, Advanced Blend Overlap Modes


      Mode                      Blend Coefficients
      --------------------      -----------------------------------
      ZERO                      (X,Y,Z)  = (0,0,0)
                                f(Cs,Cd) = 0

      SRC_NV                    (X,Y,Z)  = (1,1,0)
                                f(Cs,Cd) =  Cs

      DST_NV                    (X,Y,Z)  = (1,0,1)
                                f(Cs,Cd) =  Cd

      SRC_OVER_NV               (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =  Cs

      DST_OVER_NV               (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =  Cd

      SRC_IN_NV                 (X,Y,Z)  = (1,0,0)
                                f(Cs,Cd) =  Cs

      DST_IN_NV                 (X,Y,Z)  = (1,0,0)
                                f(Cs,Cd) =  Cd

      SRC_OUT_NV                (X,Y,Z)  = (0,1,0)
                                f(Cs,Cd) =  0

      DST_OUT_NV                (X,Y,Z)  = (0,0,1)
                                f(Cs,Cd) =  0

      SRC_ATOP_NV               (X,Y,Z)  = (1,0,1)
                                f(Cs,Cd) =  Cs

      DST_ATOP_NV               (X,Y,Z)  = (1,1,0)
                                f(Cs,Cd) =  Cd

      XOR_NV                    (X,Y,Z)  = (0,1,1)
                                f(Cs,Cd) =  0

      MULTIPLY_NV               (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = Cs*Cd

      SCREEN_NV                 (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = Cs+Cd-Cs*Cd

      OVERLAY_NV                (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = 2*Cs*Cd, if Cd <= 0.5
                                           1-2*(1-Cs)*(1-Cd), otherwise

      DARKEN_NV                 (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = min(Cs,Cd)

      LIGHTEN_NV                (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = max(Cs,Cd)

      COLORDODGE_NV             (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  0, if Cd <= 0
                                  min(1,Cd/(1-Cs)), if Cd > 0 and Cs < 1
                                  1, if Cd > 0 and Cs >= 1

      COLORBURN_NV              (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  1, if Cd >= 1
                                  1 - min(1,(1-Cd)/Cs), if Cd < 1 and Cs > 0
                                  0, if Cd < 1 and Cs <= 0

      HARDLIGHT_NV              (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = 2*Cs*Cd, if Cs <= 0.5
                                           1-2*(1-Cs)*(1-Cd), otherwise

      SOFTLIGHT_NV              (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  Cd-(1-2*Cs)*Cd*(1-Cd), 
                                    if Cs <= 0.5
                                  Cd+(2*Cs-1)*Cd*((16*Cd-12)*Cd+3), 
                                    if Cs > 0.5 and Cd <= 0.25
                                  Cd+(2*Cs-1)*(sqrt(Cd)-Cd),
                                    if Cs > 0.5 and Cd > 0.25

      DIFFERENCE_NV             (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = abs(Cd-Cs)

      EXCLUSION_NV              (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = Cs+Cd-2*Cs*Cd

      INVERT                    (X,Y,Z)  = (1,0,1)
                                f(Cs,Cd) = 1-Cd

      INVERT_RGB_NV             (X,Y,Z)  = (1,0,1)
                                f(Cs,Cd) = Cs*(1-Cd)

      LINEARDODGE_NV            (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  Cs+Cd, if Cs+Cd<=1
                                  1, otherwise

      LINEARBURN_NV             (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = 
                                  Cs+Cd-1, if Cs+Cd>1
                                  0, otherwise

      VIVIDLIGHT_NV             (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  1-min(1,(1-Cd)/(2*Cs)), if 0 < Cs < 0.5
                                  0, if Cs <= 0
                                  min(1,Cd/(2*(1-Cs))), if 0.5 <= Cs < 1
                                  1, if Cs >= 1

      LINEARLIGHT_NV            (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = 
                                  1,            if 2*Cs+Cd>2
                                  2*Cs+Cd-1,    if 1 < 2*Cs+Cd <= 2
                                  0,            if 2*Cs+Cd<=1

      PINLIGHT_NV               (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) =
                                  0,       if 2*Cs-1>Cd and Cs<0.5
                                  2*Cs-1,  if 2*Cs-1>Cd and Cs>=0.5
                                  2*Cs,    if 2*Cs-1<=Cd and Cs<0.5*Cd
                                  Cd,      if 2*Cs-1<=Cd and Cs>=0.5*Cd
                                ???
                                      
      HARDMIX_NV                (X,Y,Z) = (1,1,1)
                                f(Cs,Cd) = 0, if Cs+Cd<1
                                           1, otherwise

      Table X.2, Advanced Blend Equations


    When using one of the HSL blend equations in table X.3 as the blend
    equation, the RGB color components produced by the function f() are
    effectively obtained by converting both the non-premultiplied source and
    destination colors to the HSL (hue, saturation, luminosity) color space,
    generating a new HSL color by selecting H, S, and L components from the
    source or destination according to the blend equation, and then converting
    the result back to RGB.  In the equations below, a blended RGB color is
    produced according to the following pseudocode:

      float minv3(vec3 c) {
        return min(min(c.r, c.g), c.b);
      }
      float maxv3(vec3 c) {
        return max(max(c.r, c.g), c.b);
      }
      float lumv3(vec3 c) {
        return dot(c, vec3(0.30, 0.59, 0.11));
      }
      float satv3(vec3 c) {
        return maxv3(c) - minv3(c);
      }

      // If any color components are outside [0,1], adjust the color to
      // get the components in range.
      vec3 ClipColor(vec3 color) {
        float lum = lumv3(color);
        float mincol = minv3(color);
        float maxcol = maxv3(color);
        if (mincol < 0.0) {
          color = lum + ((color-lum)*lum) / (lum-mincol);
        }
        if (maxcol > 1.0) {
          color = lum + ((color-lum)*lum) / (maxcol-lum);
        }
        return color;
      }

      // Take the base RGB color <cbase> and override its luminosity
      // with that of the RGB color <clum>.
      vec3 SetLum(vec3 cbase, vec3 clum) {
        float lbase = lumv3(cbase);
        float llum = lumv3(clum);
        float ldiff = llum - lbase;
        vec3 color = cbase + vec3(ldiff);
        return ClipColor(color);
      }

      // Take the base RGB color <cbase> and override its saturation with
      // that of the RGB color <csat>.  The override the luminosity of the
      // result with that of the RGB color <clum>.
      vec3 SetLumSat(vec3 cbase, vec3 csat, vec3 clum)
      {
        float minbase = minv3(cbase);
        float sbase = satv3(cbase);
        float ssat = satv3(csat);
        vec3 color;
        if (sbase > 0) {
          // Equivalent (modulo rounding errors) to setting the
          // smallest (R,G,B) component to 0, the largest to <ssat>,
          // and interpolating the "middle" component based on its
          // original value relative to the smallest/largest.
          color = (cbase - minbase) * ssat / sbase;
        } else {
          color = vec3(0.0);
        }
        return SetLum(color, clum);
      }


      Mode                      Result
      --------------------      ----------------------------------------
      HSL_HUE_NV                (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = SetLumSat(Cs,Cd,Cd);

      HSL_SATURATION_NV         (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = SetLumSat(Cd,Cs,Cd);

      HSL_COLOR_NV              (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = SetLum(Cs,Cd);

      HSL_LUMINOSITY_NV         (X,Y,Z)  = (1,1,1)
                                f(Cs,Cd) = SetLum(Cd,Cs);

      Table X.3, Hue-Saturation-Luminosity Advanced Blend Equations


    When using one of the equations in table X.4 as the blend equation, the
    source color used by these blending equations is interpreted according to
    the BLEND_PREMULTIPLIED_SRC_NV blending parameter.  The blending equations
    below are evaluated where the RGB source and destination color components
    are both considered to have been premultiplied by the corresponding A
    component.

      (Rs', Gs', Bs') =
        (Rs, Gs, Bs),           if BLEND_PREMULTIPLIED_SRC_NV is TRUE
        (Rs*As, Gs*As, Bs*As),  if BLEND_PREMULTIPLIED_SRC_NV is FALSE

      Mode                      Result
      --------------------      ----------------------------------------
      PLUS_NV                   (R,G,B,A) = (Rs'+Rd, Gs'+Gd, Bs'+Bd,As'+Ad)

      PLUS_CLAMPED_NV           (R,G,B,A) = 
                                  (min(1,Rs'+Rd), min(1,Gs'+Gd),
                                   min(1,Bs'+Bd), min(1,As+Ad))

      PLUS_CLAMPED_ALPHA_NV     (R,G,B,A) = 
                                  (min(min(1,As+Ad),Rs'+Rd),
                                   min(min(1,As+Ad),Gs'+Gd),
                                   min(min(1,As+Ad),Bs'+Bd), min(1,As+Ad))

      PLUS_DARKER_NV            (R,G,B,A) = 
                                  (max(0,min(1,As+Ad)-((As-Rs')+(Ad-Rd))),
                                   max(0,min(1,As+Ad)-((As-Gs')+(Ad-Gd))),
                                   max(0,min(1,As+Ad)-((As-Bs')+(Ad-Bd))),
                                   min(1,As+Ad))

      MINUS_NV                  (R,G,B,A) = (Rd-Rs', Gd-Gs', Bd-Bs', Ad-As)

      MINUS_CLAMPED_NV          (R,G,B,A) = 
                                  (max(0,Rd-Rs'), max(0,Gd-Gs'),
                                   max(0,Bd-Bs'), max(0,Ad-As))

      CONTRAST_NV               (R,G,B,A) = 
                                 (Ad/2 + 2*(Rd-Ad/2)*(Rs'-As/2),
                                  Ad/2 + 2*(Gd-Ad/2)*(Gs'-As/2),
                                  Ad/2 + 2*(Bd-Ad/2)*(Bs'-As/2),
                                  Ad)

      INVERT_OVG_NV             (R,G,B,A) =
                                  (As*(1-Rd)+(1-As)*Rd,
                                   As*(1-Gd)+(1-As)*Gd,
                                   As*(1-Bd)+(1-As)*Bd,
                                   As+Ad-As*Ad)

      RED_NV                    (R,G,B,A) = (Rs', Gd, Bd, Ad)

      GREEN_NV                  (R,G,B,A) = (Rd, Gs', Bd, Ad)

      BLUE_NV                   (R,G,B,A) = (Rd, Gd, Bs', Ad)

      Table X.4, Additional RGB Blend Equations


    Advanced blending equations are supported only when rendering to a single
    color buffer using fragment color zero.  If any non-NONE draw buffer uses
    a blend equation found in table X.2, X.3, or X.4, the error
    INVALID_OPERATION is generated by [[Compatibility Profile:  Begin or any
    operation that implicitly calls Begin (such as DrawElements)]] [[Core
    Profile:  DrawArrays and the other drawing commands defined in section
    2.8.3]] if:

      * the draw buffer for color output zero selects multiple color buffers
        (e.g., FRONT_AND_BACK in the default framebuffer); or

      * the draw buffer for any other color output is not NONE.

    [[ The following paragraph applies to NV_blend_equation_advanced only. ]]

    When using advanced blending equations, applications should split their
    rendering into a collection of blending passes, none of which touch an
    individual sample more than once.  The results of blending are undefined
    if the sample being blended has been touched previously in the same pass.
    The command

      void BlendBarrierNV(void);

    specifies a boundary between passes when using advanced blend equations.
    Any command that causes the value of a sample to be modified is considered
    to touch the sample, including clears, blended or unblended primitives,
    BlitFramebuffer copies, and direct updates by commands such as
    TexSubImage2D.

    [[ The following paragraph applies to NV_blend_equation_advanced_coherent
       only. ]]

    When using advanced blending equations, blending is typically done
    coherently and in primitive order.  When an individual sample is covered
    by multiple primitives, blending for that sample is performed sequentially
    in the order in which the primitives were submitted.  This coherent
    blending is enabled by default, but can be enabled or disabled by calling
    Enable or Disable with the symbolic constant BLEND_ADVANCED_COHERENT_NV.
    If coherent blending is disabled, applications should split their
    rendering into a collection of blending passes, none of which touch an
    individual sample more than once.  When coherent blending is disabled, the
    results of blending are undefined if the sample being blended has been
    touched previously in the same pass.  The command

      void BlendBarrierNV(void);

    specifies a boundary between passes when using advanced blend equations.
    Any command that causes the value of a sample to be modified is considered
    to touch the sample, including clears, blended or unblended primitives,
    BlitFramebuffer copies, and direct updates by commands such as
    TexSubImage2D.


Additions to Chapter 5 of the OpenGL 4.1 Specification (Special Functions)

    None.

Additions to Chapter 6 of the OpenGL 4.1 Specification (State and
State Requests)

    None.

Additions to Appendix A of the OpenGL 4.1 Specification (Invariance)

    None.

Additions to the AGL/GLX/WGL/EGL Specifications

    None.

GLX Protocol

    !!! TBD

Dependencies on OpenGL 4.0

    If OpenGL 4.0 is not supported, references to the BlendEquationi API should
    be removed.

Dependencies on OpenGL 4.1 (Core Profile)

    This extension throws an INVALID_OPERATION when Begin is called if advanced
    blend equations are used in conjunction with multiple draw buffers.  For
    the core profile of OpenGL 4.1 (and other versions of OpenGL), there is no
    Begin command; instead, the error is thrown by other rendering commands
    such as DrawArrays.  The language in this specification documenting the
    error has separate versions for the core and compatibility profiles.

Dependencies on OpenGL 4.3 or later (any Profile)

    References to Chapter 4 are replaced with references to Chapter 17 (Writing
    Fragments and Samples to the Framebuffer).
    References to section 4.1.8 are replaced with references to section 17.3.8.
    References to Table 4.1 are replace with references to Table 17.1.
    References to section 2.1.1 are replaced with references to section 2.3.3.

Dependencies on OpenGL ES 2.0

    If unextended OpenGL ES 2.0 is supported, references to BlendEquationi,
    BlendEquationSeparatei, GetInteger64v, and GetDoublev should be ignored.

    Ignore any references to multiple draw buffers if EXT_draw_buffers or
    NV_draw_buffers is not supported.

Dependencies on EXT_blend_minmax

    Requires EXT_blend_minmax on OpenGL ES 2.0 implementations and references
    to MIN and MAX should be replace by references to MIN_EXT and MAX_EXT as
    introduced by that extension.

Dependencies on OpenGL ES 3.0

    If unextended OpenGL ES 3.0 is supported, references to BlendEquationi,
    BlendEquationSeparatei, and GetDoublev should be ignored.

Dependencies on NV_path_rendering

    When NV_path_rendering is supported, covering geometry generated by the
    commands CoverFillPathNV, CoverFillPathInstancedNV, CoverStrokePathNV, and
    CoverStrokePathInstancedNV will automatically be blended coherently
    relative to previous geometry when using the blend equations in this
    extension.  This guarantee is provided even on implementations supporting
    only NV_blend_equation_advanced.

    Insert the following language after the discussion of the BlendBarrierNV()
    command for both extensions:

      [[ For NV_blend_equation_advanced only: ]]

      The commands CoverFillPathNV, CoverFillPathInstancedNV,
      CoverStrokePathNV, and CoverStrokePathInstancedNV are considered to
      start a new blending pass, as though BlendBarrierNV were called prior to
      the cover operation.  If a cover primitive is followed by subsequent
      non-cover primitives using advanced blend equations and touching the
      same samples, applications must call BlendBarrierNV after the cover
      primitives to ensure defined blending results.

      [[ For NV_blend_equation_advanced_coherent, the language immediately
         above should be used, but the first sentence should be prefixed with
         "When coherent blending is disabled, ...". ]]

Errors

    If any non-NONE draw buffer uses a blend equation found in table X.2, X.3,
    or X.4, the error INVALID_OPERATION is generated by Begin or any operation
    that implicitly calls Begin (such as DrawElements) if:

      * the draw buffer for color output zero selects multiple color buffers
        (e.g., FRONT_AND_BACK in the default framebuffer); or

      * the draw buffer for any other color output is not NONE.

    If BlendParameteriNV is called and <pname> is not 
    BLEND_PREMULTIPLIED_SRC_NV or BLEND_OVERLAP_NV the error INVALID_ENUM is
    generated.

    If BlendParameteriNV is called with <pname> set to
    BLEND_PREMULTIPLIED_SRC_NV the error INVALID_ENUM is generated if <param>
    is not TRUE or FALSE.

    If BlendParameteriNV is called with <pname> set to BLEND_OVERLAP_NV the
    error INVALID_ENUM is generated if <param> is not one of UNCORRELATED_NV,
    DISJOINT_NV, or CONJOINT_NV.

New State
                                             Initial
    Get Value             Type  Get Command   Value         Description               Sec    Attribute
    --------------------  ----  ------------  ------------  ------------------------  -----  ------------
    BLEND_ADVANCED_        B    IsEnabled     TRUE          are advanced blending     4.1.8  color-buffer
      COHERENT_NV                                           equations guaranteed to
                                                            be evaluated coherently?
    BLEND_PREMULTIPLIED_   B    GetBooleanv   TRUE          use premultiplied src     4.1.8  color-buffer
      SRC_NV                                                colors with advanced
                                                            blend equations
    BLEND_OVERLAP_NV       Z3   GetIntegerv   UNCORRELATED  correlation of src/dst    4.1.8  color-buffer
                                                _NV         coverage within a pixel

    Note:  The BLEND_ADVANCED_COHERENT_NV enable is provided if and only if
    the NV_blend_equation_advanced_coherent extension is supported.  On
    implementations supporting only NV_blend_equation_advanced, this enable is
    considered not to exist.

New Implementation Dependent State

    None.

NVIDIA Implementation Details

    Older versions of this extension specification and early shipping
    implementations supported the COLORDODGE_NV and COLORBURN_NV equations
    without the special case discussed in issue (34). This should be fixed for
    newer driver releases.

Issues

    (1) How should these new blending operations be supported?

      RESOLVED:  Provide a separate blend equation for each of the various
      blending operations.

    (2) Many of these blending operations involve complicated computations on
        the RGB color components, but corresponding alpha operations are
        typically very simple.  How should blending on the alpha channel work?

      RESOLVED:  Each new blend equation provides one equation for color and
      another for alpha.  In this extension, separate advanced blend equations
      for color and alpha are not supported; BlendEquationSeparate does not
      accept these enums.

      This extension contemplated separate blend equations for RGB and alpha,
      perhaps with only basic equations for alpha, but we chose to tie RGB and
      alpha blending together for simplicity.

    (3) Should we provide explicit support for premultiplied colors?

      RESOLVED:  Yes.  Many of the imaging APIs supporting similar blend
      equations use premultiplied colors, some exclusively.  Additionally,
      many equations are simpler to express and compute with premultiplied
      colors.

      In this extension, we choose to treat the destination colors and the
      blend result as premultiplied.  We considered providing a blend
      parameter supporting non-premultiplied destinations, but chose to
      support only premultiplied destinations for mathematical simplicity.

    (4) Should we support blending where some, but not all, colors are
        premultiplied?  For example, there may be cases where the source
        fragment colors are not premultiplied, but where the destination
        colors are premultiplied.

      RESOLVED:  Yes, we will provide support for non-premultiplied fragment
      colors (via a blending parameter), in which case the RGB color
      components are multiplied by alpha prior to blending.  

      We considered requiring premultiplication in the fragment shader, but
      opted to provide a fixed-function premultiply operation for cases where
      it was inconvenient to modify the fragment shader to perform the
      multiplication, or where no fragment shader is executed (e.g.,
      fixed-function fragment processing, blits via the NV_draw_texture
      extension).

    (5) Should we support different types of correlation between source and
        destination coverage in partially covered pixels?  If so, how?

      RESOLVED:  We will provide a blend parameter allowing for multiple
      versions of many blending equations based on the "correlation" between
      source and destination coverage.  For pixels with partial opacity, there
      might be three different blend cases:  (a) where the portions of the
      pixel covered by the primitives are considered to have minimal overlap
      (e.g., abutting primitives in a mesh), (b) where the portions of the
      pixel covered by the primitives are considered to have maximal overlap
      (e.g., overlapping geometry), (c) where the portions of the pixel
      covered by the primitives are considered uncorrelated.

    (6) Should we support swapping source and destination coverage in advanced
        blends?  If so, how?

      RESOLVED:  In the current version, we don't support fully general
      swapping.  We do provide several pairs of blend equations that are
      equivalent, other than swapping source and destination colors.  For
      example, we provide complementary blend equations SRC_OVER_NV, where the
      source color is considered to be "over" the destination, and
      DST_OVER_NV, where the destination color is considered to be "over the
      source.  Having pairs of equations such as "SRC_OVER" and "DST_OVER"
      seems to be common practice in various imaging APIs.

      Alternately, we could provide a blend parameter that simply swaps source
      and destination for arbitrary blend equations.  In the example above, we
      could provide a single blend equation OVER_NV, where the source color is
      considered "over" when unswapped and the destination color is considered
      "over" when swapped.

    (7) Should we generalize the blending operation, replacing the notions of
        "source" and "destination" colors with more generic "A" and "B"
        parameters, which might be obtained from a variety of sources
        (fragment color, one of <N> color attachment points, some additional
        source of textures/images)?

      RESOLVED:  Not in this extension; the only blending operation we support
      takes a fragment color (which could be obtained from an arbitrary
      source, either through a fragment shader, fixed function fragment
      processing, or an imaging API such as NV_draw_texture) and a destination
      color, performs a blend, and stores the result in the buffer from which
      the destination color was extracted.

    (8) How should we expose the various combinations of blending modes?

      RESOLVED:  The base blending equation is specified by the same
      BlendEquation() API supported for regular OpenGL blending.  Additional
      parameters (such as pre-multiplied source colors, overlap mode, source
      destination swapping, input selection) can be specified via the
      BlendParameteriNV() API.

      We could provide for a "general" blend equation API specifying multiple
      parameters at once, such as:

        void BlendEquationGeneralNV(enum blend, enum overlap, 
                                    boolean swapSrcDst);

      but that API would require applications to pass parameters that are
      always the same (e.g., overlap as UNCORRELATED_NV) and wouldn't be
      easily extensible.  Note that there are several features that we've
      chosen not to include but might be usefully added as blend parameters in
      the future -- see issues (3), (6), and (7), for example.

    (9) What limitations apply to the new blend modes?

      RESOLVED:  In the current implementation, these blend equations are not
      supported with more than one color buffer; if this is attempted, a
      draw-time error is generated.  This limitation is similar in nature to
      one for dual-source blending, which implementations are not required to
      support in conjunction with multiple color buffers.  This limitation may
      be relaxed in a future version of this extension.

    (10) What precision is used in the computations for these blending
         equations?

      RESOLVED:  There are no minimum precision requirements specified in
      OpenGL 4.1, though one would expect implementations to blend with at
      least the precision used to store destination color components.  This
      extension provides this as a minimum baseline for existing blending
      equations.

      For the new equations, we specify a minimum precision that is the
      smaller of the precision of the destination buffer or the precision of
      16-bit floating-point computations.  For most formats, this meets the
      limit for basic blend equations.  However, there may be precision loss
      if these new blending equations are used with 12-bit unsigned normalized
      components, 16-bit unsigned or signed normalized components, or 32-bit
      floating-point components.

      This restriction is specified so that implementations are not required
      to support the large number of blending equations specified here with
      full 32-bit floating-point computations.

    (11) When targeting a fixed-point buffer, are input color components
         clamped to [-1,1] for signed normalized color buffers or to [0,1] for
         unsigned normalized color buffers?

      RESOLVED:  We will use the same clamping behavior as for basic blend
      equations, where fragment color components are clamped to [0,1] prior to
      blending for unsigned normalized color targets.

      Note that the OpenGL 4.1 specification, against which this spec is
      written, had an oversight related signed normalized color buffers.  It
      specifies [0,1] clamping for all "fixed point" targets, which is clearly
      not desired for signed normalized color buffers.  Fragment shader color
      outputs should be clamped to [-1,+1] in this case; this was fixed in
      OpenGL 4.2 (bug 6849).

    (12) What happens when converting a premultiplied color with an alpha of
         zero to a non-premultiplied color?

      RESOLVED:  We specify that a premultiplied color of (0,0,0,0) should
      produce non-premultiplied (R,G,B) values of (0,0,0).  A premultiplied
      color with an alpha of zero and a non-zero R, G, or B component is
      considered to be ill-formed and will produce undefined blending results.

      For a non-premultiplied color (R',G',B',A'), the corresponding
      premultiplied color (R,G,B,A) should satisfy the equation:

        (R,G,B,A) = (R'*A', G'*A', B'*A', A')

      If the alpha of a non-premultiplied color is zero, the corresponding
      premultiplied color (R,G,B,A) should be (0,0,0,0).

      We specify that ill-formed premultiplied colors produce undefined
      blending results to enable certain performance optimizations.  In many
      of these blending equations, the alpha component used as a denominator
      to compute the non-premultiplied color ends up being multiplied by the
      same alpha component in the coverage, resulting in cancellation.  For
      example, implementations may want to substitute a premultiplied
      destination color into the last term of the basic blend equation:

        R = f(Rs',Rd')*p0(As,Ad) + Y*Rs'*p1(As,Ad) + Z*Rd'*p2(As,Ad)
          =                                    ... + Z*Rd'*(Ad*(1-As))
          =                                    ... + Z*(Rd'*Ad)*(1-As)
          =                                    ... + Z* Rd * (1-As)

      This substitution would be invalid for ill-formed premultiplied
      destination colors.  We choose to specify undefined results for invalid
      input colors rather than requiring implementations to skip such
      optimizations or include logic to check for zero alpha values for each
      input.

    (13) Should we provide "advanced" RGB blend equations for modes commonly
         used in dedicated imaging APIs that can already be expressed with
         current OpenGL blending modes?

      RESOLVED:  Yes; we will provide a number of "advanced" blend equations
      for basic computations that can be done with existing blend equations.
      This allows applications wanting to use these advanced modes to use them
      exclusively, without having to figure out which blends are not supported
      and generate separate BlendEquation/BlendFunc state for each.

    (14) How do the advanced RGB blend equations interact with sRGB color
         buffers?  In particular, how does it interact with storing
         premultiplied color values in the framebuffer?

      RESOLVED:  When targeting an sRGB color buffer with the blend equations
      in this extension, we will convert the destination colors from sRGB to
      linear and will convert the linear blend result back to sRGB when
      writing it to the framebuffer.  This approach is no different from
      regular blends.

      sRGB conversions will affect premultiplied colors differently than
      non-premultiplied colors since:

        linear_to_srgb(C*A) != A * linear_to_srgb(C)

      When storing an sRGB-encoded value into an sRGB texture or renderbuffer,
      we expect that the values will be extracted as sRGB colors in a
      subsequent texturing, blending, or display operation.  The fetched sRGB
      color components will be converted back to linear.  Except from rounding
      errors in converting the color components to fixed-point, converting to
      and from sRGB will not modify the color, with or without
      premultiplication.

    (15) The HSL blend equations are "color surgery" operations where
         components from the source and destination colors are mixed.  Are
         there any problems using these equations with premultiplied color
         components?

      RESOLVED:  Like all of the "f/X/Y/Z" blends, the function f() in HSL
      blend equations are expressed in terms of non-premultiplied colors,
      which implies a division operation prior to evaluating f().  However, it
      may be possible to perform some or all of the blending operation using
      pre-multiplied colors directly.  In particular, the luminosity and
      saturation of a color with components scaled by alpha is equal to alpha
      times the luminosity or saturation of the un-scaled color:

        lumv3(C*A) = A * lumv3(C)
        satv3(C*A) = A * satv3(C)

    (16) How should we express the blending equations?

      RESOLVED:  In general, we will use the formulation found in the PDF and
      SVG specifications, which define each blend in terms of four parameters:

        * a function f(Cs,Cd) specifies the blended color contribution in the
          portion of the pixel containing both the source and destination;

        * a constant X specifies whether the region containing both the source
          and destination contributes to the final alpha;

        * a constant Y specifies whether the region containing only the source
          contributes to the final color and alpha; and

        * a constant Z specifies whether the region containing only the
          destination contributes to the final color and alpha.

       This formulation is relatively compact and nicely illustrates the
       contributions from the three relevant combinations of source and
       destination coverage; the portion of the pixel covered by neither the
       source nor the destination contributes nothing to color or alpha.

       Additionally, we specify three functions p0(As,Ad), p1(As,Ad), and
       p2(As,Ad) specifying the relative portion of the pixel covered by both
       the source and destination, just the source, and just the destination,
       respectively.  These functions are defined according to the overlap
       blend parameter; the most common mode (UNCORRELATED) defines:

         p0(As,Ad) = As*Ad
         p1(As,Ad) = As*(1-Ad)
         p2(As,Ad) = Ad*(1-As)

       There are certain special-purpose blending equations that don't fit
       this general model (modes that mix RGB or HSL components from the
       source and destination).  These blends don't fit nicely into the
       mathematical formulas above and are instead defined separately as a
       component-by-component operation.

    (17) How should we express the equations for the HSL blend equations?

      RESOLVED:  The equations used by this specification are loosely adapted
      from similar code in the version 1.7 of the PDF (Portable Document
      Format) specification.  The equations have been modified to use
      GLSL-style "vec3" syntax.  Additionally, they use vector math in the
      pseudocode overriding the saturation of a base color instead of using
      "C_min", "C_mid", and "C_max" syntax effectively defining references to
      the three components of the base color.

      Alternately, we could have specified functions for converting (R,G,B)
      colors to and from an (H,S,L) color space.  But we decided not to do
      that because actual (H,S,L) colors are never used in the pipeline.

    (18) What issues apply to the PLUS and MINUS equations?

      RESOLVED:  The PLUS and MINUS equations provide arithmetically simple
      operations; we simply perform a component-wise add or subtract
      operations.  The most interesting question is how and where clamping is
      performed.  The original Porter-Duff compositing specification provided
      a "plus" equation intended to support blending between two images,
      effectively performing:

        weight * image1 + (1-weight) * image2

      If the components of <image1>, <image2>, and <weight> are all in [0,1],
      there is no need for clamping.  However, in a general add with no
      <weight> built in, there is no guarantee that adding components of two
      images will remain inside the range [0,1].  When using fixed-point
      unsigned normalized color buffers, the sum will automatically be clamped
      to [0,1] when stored in the framebuffer.  However, there may be cases
      with floating-point color buffers where not clamping the sum also makes
      sense.

      Additionally, when storing premultiplied colors, it may also be
      desirable to clamp R/G/B components to the range [0,A].  Premultiplied
      colors effectively store "R*A" in the R channel, where "R" is the
      non-premultiplied color and A is alpha.  Clamping this value to A
      ensures that the non-premultiplied form of R is in [0,1].

      To handle all possible cases, we provide five "PLUS" and "MINUS"
      equations.

        PLUS_NV:  Add color and alpha components without clamping.

        PLUS_CLAMPED_NV:  Add color and alpha components; clamp each sum to
        1.0.

        PLUS_CLAMPED_ALPHA_NV:  Add color and alpha components.  Clamp the
        alpha sum to 1.0; clamp the color sums to the alpha result (i.e., the
        clamped alpha sum).  Note that if premultiplied inputs are clamped
        properly where 0<=R,G,B<=A, this equation isn't needed since the color
        sums will always be less than the alpha sum.

        MINUS_NV:  Subtract the source color and alpha components from the
        destination without clamping.

        MINUS_CLAMPED_NV:  Subtract the source color and alpha components from
        the destination; clamp the difference to 0.0.

      We don't bother clamping in "unexpected" direction.  We don't bother
      clamping sums to be greater than or equal to zero or differences to be
      less than or equal to one; either case would require an unclamped input
      with a negative component.

      Note that when blending to an unsigned fixed-point buffer, the clamped
      and non-clamped versions of "PLUS" and "MINUS" produce the same results,
      since inputs and outputs are both clamped to [0,1].

      Note that the LINEARDODGE_NV equation is another form of "PLUS"; in the
      area of intersection, the source and destination colors are added and
      clamped to 1.0.

    (19) Should we provide a blend parameter to clamp the destination color
         (when read) to [0,1]?  What about clamping premultiplied RGB
         components to [0,a]?

      RESOLVED:  No.  We expect the most common use case to involve unsigned
      normalized color buffers, where components will automatically be clamped
      to [0,1] by virtue of how they're stored in the framebuffer.  It doesn't
      seem worth the trouble to add a clamp-on-read feature to clamp to [0,a]
      when it seems easy enough to program colors to stay in range.

    (20) Should we provide a blend parameter to clamp final color or alpha
         output components to [0,1]?  What about clamping premultiplied RGB
         outputs to [0,a]?

      RESOLVED:  As above, when writing the blend results to unsigned
      normalized targets, output components will automatically be clamped to
      [0,1] by virtue of how they're stored in the framebuffer.  It doesn't
      seem worth the trouble to clamp to [0,a], either.  Most of the blend
      equations supported by this extension will produce outputs with
      premultiplied color component values in the range [0,a] as long as the
      inputs also have that property.  One exception is PLUS_NV, but we
      explicitly provide a PLUS_CLAMPED_ALPHA_NV equation to for that case.

    (21) Should we provide an equation like the VG_BLEND_SOFTLIGHT_SVG_KHR
         blending equation in the KHR_advanced_blending extension to OpenVG?

      RESOLVED:  No.  The KHR_advanced_blending appears to have specified a
      equation implementing the "soft-light" compositing property in a working
      draft of a SVG 1.2 specification, as described here:

        http://www.w3.org/TR/2004/WD-SVG12-20041027/
          rendering.html#compositing

      This version of the specification appears to have been abandoned.  The
      equations for the "soft-light" property in the SVG Compositing
      Specification at:

        http://www.w3.org/TR/SVGCompositing/

      match the SOFTLIGHT_NV equation provided by this extension and
      VG_BLEND_SOFTLIGHT_KHR (no "SVG") in KHR_advanced_blending.

      Additionally, the equations in the SVG 1.2 draft and the
      KHR_advanced_blending extension both appear to contain clear errors in
      the first and second cases.  Both begin with "(cd*(as-(1-cd/ad)*..." in
      the KHR spec but should be "(cd*(as+(1-cd/ad)*...".  Both of these sign
      errors are corrected in the "SVG" functions in this extension.  With the
      errors, there is a local minimum at Cs=0.5 (where we switch from the
      first form to the second or third) and the function has a major
      discontinuity at Cd=0.125 when Cs>0.5 (where we switch from the second
      form to the third).  For example, when Cs=0.8 and Cd=0.125, the second
      form of the KHR extension would generate a result of -0.00625 and the
      third form would generate a result of ~0.26213.  Note that the corrected
      equations still aren't continuous at Cd=0.125; the fixed second and
      third forms generate 0.25625 and 0.26213, respectively, when Cs=0.8 and
      Cd=0.125.

    (22) What issues apply to the INVERT and INVERT_OVG_NV equations?

      RESOLVED:  The INVERT and INVERT_OVG_NV equations were included to
      provide functionality similar to the same VG_BLEND_INVERT_KHR blend
      equation provided by the KHR_advanced_blending extension to OpenVG and
      similar equations in a few other compositing APIs/standards.

      Unfortunately, the equation specified by the KHR extension has issues.
      The apparent intent of this blend equation is to use the source alpha to
      blend between the destination color and an inverted form of the
      destination color.  This description conceptually matches the
      description in the KHR extension:

        (1 - asrc) * c'dst + asrc * (1 - c'dst)

      However, since source and destination colors are premultiplied, the
      expression "1-c'dst" doesn't correctly invert the destination color.  To
      invert a premultiplied destination color, "adst-c'dst" should be used.
      For example, if the premultiplied destination color is 50% gray and 50%
      opaque (adst=0.5), the RGBA destination color will be
      (0.25,0.25,0.25,0.5).  Inverting the color components via "1-c'dst"
      would yield RGB component values of 0.75, which isn't consistent with an
      alpha of 0.5.  Inverting via "adst-c'dst" would yield correct RGB
      component values of 0.25.

      Additionally, the alpha computed for this equation in the KHR extension
      is the standard "asrc+adst*(1-asrc)", equivalent to X=Y=Z=1 in our
      normal formulation.  However, given that the source color doesn't
      contribute at all, having "Y=1" doesn't make a whole lot of sense.  The
      INVERT equation used in this extension uses X=Z=1 and Y=0, which means
      that blending with this equation never changes destination alpha.

      We provide a separate blend equation INVERT_OVG_NV to provide 
      compatibility with the formulation in the KHR extension.  The math in
      the KHR extension does perform a "valid" blending operation -- it will
      produce results that remain in [0,1] when inputs are in [0,1], and its
      results are continuous.  It can't be expressed directly via our f/X/Y/Z
      parameterization, but it does match our general f/X/Y/Z model if you
      consider all three areas to contribute where:

        * the intersection area contributes the inverted destination color
        * the destination-only area contributes the destination color
        * the source-only area contributes full white

      Note that INVERT and INVERT_OVG_NV equations are mathematically
      equivalent when the destination is opaque (i.e., adst=1.0); in this
      case, "1-c'dst" and "adst-c'dst" are equivalent.  In our f/X/Y/Z model,
      the full destination coverage means there is no "source-only" area in
      this case.

    (23) What issues apply to the PLUS_DARKER_NV blend equation?

      RESOLVED:  The PLUS_DARKER_NV equation corresponds to an equation
      provided in the Quartz 2D API from Apple.  The public documentation for
      this equation specifies the color computed by this operation as:

        R = MAX(0, 1 - ((1 - D) + (1 - S)))

      This equation appears to want to invert the source and destination
      colors, add the two inverted colors, and then invert the result.

      However, this equation appears to assume opaque source and destination
      colors.  As noted in the discussion for INVERT_OVG_NV, inverting a color
      via "1-C" doesn't make any sense.  We've reformulated the equations to
      use pre-multipled colors and invert with "A-C" in a manner similar to
      that described in this email thread:

        http://www.mail-archive.com/whatwg@lists.whatwg.org/msg06536.html

      which appears to be the "darker" mode implemented in the Safari browser
      (at least in 2007).  Our formulation is equivalent to the one in the
      Quartz 2D documentation when As=Ad=1.

    (24) Should we apply the f/X/Y/Z formulation to blend equations where the
         equations can be expressed this way only if one or more of X, Y, or
         Z are neither zero nor one?

      RESOLVED:  No.  The f/X/Y/Z model subdivides a pixel into four regions
      based on the alpha of the source and the destination, three of which
      (intersection, source only, destination only) either contribute or don't
      contribute color and coverage based on the given blend equation.  The
      figure below depicts a pixel where the source and destination both have
      coverage of 0.5 (50%).  The picture assigns source coverage to the upper
      left portion of the pixel and the destination coverage to the upper
      right, and assumes an UNCORRELATED model.  In this case, the pixel is
      divided into four areas of equal size.  The area of intersection is at
      the top, and its color and coverage are controlled by the f() and X
      parameters.  The source-only and destination-only regions are on the
      left and right, respectively, and color and coverage are both controlled
      by the Y and Z parameters.

                    +-----------+
                    |\_  f/X  _/|
          source    |  \_   _/  |  destination
          (upper ==>| Y  \_/  Z |    (upper
           left)    |   _/ \_   | <== right)
                    | _/     \_ |
                    |/         \|
                    +-----------+

      The PLUS_NV equation could be expressed with f(Cs,Cd) = Cs+Cd, X=2, Y=1,
      and Z=1.  The X=2 term effectively has the source and destination *both*
      contribute coverage in the area of intersection.  The MINUS_NV equation
      could be expressed with f(Cs,Cd) = Cd-Cs, X=1, Y=-1, and Z=1.  The Y=-1
      term effectively has the source-only portion of the pixel *remove*
      coverage.  Both of these don't match the physical model, and would yield
      odd results when combined with conjoint or disjoint overlap modes.

    (25) Should we provide more specialized versions of CONJOINT_NV and
         DISJOINT_NV?

      RESOLVED:  Not in this extension.  In the future, we could add new
      overlap modes such as:

        NON_INTERSECTING_NV:  Like DISJOINT_NV, except that it assumes that
        As+Ad<=1.  This might be interesting when rendering polygons with
        POLYGON_SMOOTH?

        DST_INSIDE_NV, SRC_INSIDE_NV:  Like CONJOINT_NV, except that it
        assumes that the destination coverage is fully inside the source or
        vice versa.  For DST_INSIDE, the p0/p1/p2 terms would be Ad, As-Ad,
        and 0, respectively.

      For all three of these modes, the specialized versions would have
      simpler and possibly more efficient math.  We're not going to add any of
      these modes in this extension, however.

    (26) Should the blend equations have a common prefix (e.g.,
    "BLEND_SRC_OVER") or just use forms without a prefix?

      RESOLVED:  Use forms without a prefix where the tokens are only used in
      the context of blending (i.e., via the BlendEquation API).  We will use
      a "BLEND_" prefix to identify BlendParameter <pname> values because
      those tokens can also be used in the general GetIntegerv API.  Note that
      in current OpenGL, some parameters have their own Get* API (e.g.,
      TexParameter), while others use the general GetInteger queries (e.g.,
      PointParameter).

    (27) Should we use standard GL enums for the blend equations that already
    have these names?

      RESOLVED:  Yes, to minimize the number of new enums.  The primary risk
      is that reusing standard enum definitions would be problematic if a
      future core version wanted to use these parameters in the same place
      with a different meaning.  However, all such names are in common use in
      various compositing standards and our semantics are consistent with
      those standards.

    (28) What other APIs support blend equations similar to the ones provided
         here, and how does the feature set compare?

      RESOLVED:  Khronos' OpenVG 1.1 vector graphics library provides a
      variety of basic blending equations, with additional modes provided by
      the KHR_advanced_blending extension:

      * http://www.khronos.org/registry/vg/specs/openvg-1.1.pdf
      * http://www.khronos.org/registry/vg/extensions/KHR/advanced_blending.txt

      The World Wide Web Consortium (W3C)'s Scalable Vector Graphics format
      supports a variety of blending equations in its compositing
      specification:

      * http://www.w3.org/TR/SVGCompositing

      W3C also has a CSS standard (Compositing and Blending Level 1):

      * http://www.w3.org/TR/compositing-1/

      Adobe's widely-used Portable Document Format (PDF) specification
      provides numerous blending equations in its "Transparency" section:

      * http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/
          pdf_reference_1-7.pdf

      Adobe's SWF (Flash) File Format Specification

      * http://www.adobe.com/go/swfspec

      Various "2D" graphics APIs, including Oracle's JavaFX, Apple's Quartz
      2D, Qt's QPainter class, and X Window System's X Rendering Extension
      also support a variety of blending equations:

      * http://docs.oracle.com/javafx/2/api/javafx/scene/effect/BlendMode.html

      * http://developer.apple.com/library/ios/#documentation/GraphicsImaging/
          Reference/CGContext/Reference/reference.html

      * http://doc.qt.digia.com/4.7/qpainter.html#composition-modes

      * http://www.x.org/releases/current/doc/renderproto/renderproto.txt

      The following table indicates the set of blend equations from this
      extension that are supported in these various standards or APIs.  "X"
      indicates that the equation is supported.  For OpenVG, "E" indicates
      that the equation is supported by the KHR_advanced_blending extension.
      "XO" that the indicates that the equation is supported with conjoint and
      disjoint overlap modes; others support only the uncorrelated overlap
      mode.

        Blending Equation       OVG   SVG   PDF   SWF   JFX   Q2D   QPT   XRE
        --------------------   ----- ----- ----- ----- ----- ----- ----- -----
        ZERO                     E     X     -     -     -     X     X     XO
        SRC_NV                   X     X     -     X     -     X     X     XO
        DST_NV                   E     X     -     -     -     -     X     XO
        SRC_OVER_NV              X     X     X     X     X     X     X     XO
        DST_OVER_NV              X     X     -     -     -     X     X     XO
        SRC_IN_NV                X     X     -     -     -     X     X     XO
        DST_IN_NV                X     X     -     X     -     X     X     XO
        SRC_OUT_NV               E     X     -     -     -     X     X     XO
        DST_OUT_NV               E     X     -     X     -     X     X     XO
        SRC_ATOP_NV              E     X     -     -     X     X     X     XO
        DST_ATOP_NV              E     X     -     -     -     X     X     XO
        XOR_NV                   E     X     -     -     -     X     X     XO
        MULTIPLY_NV              X     X     X     X     X     X     X     X
        SCREEN_NV                X     X     X     X     X     X     X     X
        OVERLAY_NV               E     X     X     X     X     X     X     X
        DARKEN_NV                X     X     X     X     X     X     X     X
        LIGHTEN_NV               X     X     X     X     X     X     X     X
        COLORDODGE_NV            E     X     X     -     X     X     X     X
        COLORBURN_NV             E     X     X     -     X     X     X     X
        HARDLIGHT_NV             E     X     X     X     X     X     X     X
        SOFTLIGHT_NV             E     X     X     -     X     X     X     X
        DIFFERENCE_NV            E     X     X     X     X     X     X     X
        EXCLUSION_NV             E     X     X     -     X     X     X     X
        INVERT                   -     -     -     X     -     -     -     -
        INVERT_RGB_NV            -     -     -     -     -     -     -     -
        LINEARDODGE_NV           E     -     -     -     -     -     -     -
        LINEARBURN_NV            E     -     -     -     -     -     -     -
        VIVIDLIGHT_NV            E     -     -     -     -     -     -     -
        LINEARLIGHT_NV           E     -     -     -     -     -     -     -
        PINLIGHT_NV              E     -     -     -     -     -     -     -
        HARDMIX_NV               E     -     -     -     -     -     -     -
        HSL_HUE_NV               -     -     X     -     -     X     -     X
        HSL_SATURATION_NV        -     -     X     -     -     X     -     X
        HSL_COLOR_NV             -     -     X     -     -     X     -     X
        HSL_LUMINOSITY_NV        -     -     X     -     -     X     -     X
        PLUS_NV /
        PLUS_CLAMPED_NV /        X     X     -     X     X     X     X     X
        PLUS_CLAMPED_ALPHA_NV
        PLUS_DARKER_NV           -     -     -     -     -     X     -     -
        MINUS_NV /               E     -     -     X     -     -     -     -
        MINUS_CLAMPED_NV
        CONTRAST_NV              -     -     -     -     -     -     -     -
        INVERT_OVG_NV            E     -     -     -     -     -     -     -
        RED_NV                   -     -     -     -     X     -     -     -
        GREEN_NV                 -     -     -     -     X     -     -     -
        BLUE_NV                  -     -     -     -     X     -     -     -

        OpenGL COLOR_LOGIC_OP    -     -     -     -     -     -     X     -
        (not in this extension)

        Notes:  

        * The PLUS_NV, PLUS_CLAMPED_NV, and PLUS_CLAMPED_ALPHA_NV equations
          are very similar and may be indistinguishable when the destination
          buffer components are stored in normalized [0,1] numeric spaces, as
          is the case in most of these standards.  The MINUS_NV and
          MINUS_CLAMPED_NV equations behave similarly.

        * The SWF specification has a mode called "invert", but it's not clear
          whether the mode is implemented using INVERT, INVERT_OVG_NV, or some
          other equation.

    (29) Should we provide an extension that can be supported on
         implementations that may not provide fully coherent blending when
         using the new equations?  If so, how will this support be provided
         and what limitations apply?

      RESOLVED:  Yes, this functionality is useful not just for general 3D
      rendering, but also for 2D rendering operations (where the primitives
      rendered may be less complex).  As indicated in the issue above, the
      blend equations provided by this extension are already very commonly
      used in 2D rendering.  Accelerating them on a wide range of GPUs, old
      and new, would be very useful.

      Older NVIDIA GPUs are able to support these blending equations as long
      as rendering is split into distinct passes and no pixel is touched more
      than once in any given pass.  For such GPUs, we specify that the results
      of blending are undefined if a single pixel (or sample) is touched more
      than once in a pass, and provide the command BlendBarrierNV() to allow
      applications to delimit boundaries between passes.  As long as rendering
      commands can be split into passes with barriers, advanced blending will
      work "normally" even on these older GPUs.

      Since there are two distinct levels of capability, we will advertise two
      different extension string entries:

        - GL_NV_blend_equation_advanced:  Provides the new blending
          functionality without support for full coherence (older GPUs).

        - GL_NV_blend_equation_advanced_coherent:  Provides the new blending
          functionality with full coherence.

      Since the functionality of these two extensions is nearly identical, we
      document them in a single extension specification.

    (30) On implementations that don't support fully coherent blending, should
         we provide any convenience features so that "2D" applications aren't
         required to manually sprinkle BlendBarrierNV() throughout the code?

      RESOLVED:  Yes.  When using NV_blend_equation_advanced in conjunction
      with NV_path_rendering commands like CoverFillPathNV and
      CoverStrokePathNV, the driver will assist in ensuring coherent and
      properly ordered blending by inserting implicit blend barriers before
      rendering each cover primitive.

    (31) When we generate fragments using the automatic coherence guarantees
         from NV_path_rendering commands like CoverFillPathNV, what happens if
         a pixel touched by CoverFillPathNV had already been touched by a
         previous non-NVpr rendering command without an intervening call to
         BlendBarrierNV?  What happens if a pixel touched by CoverFillPathNV
         is subsequently touched by a subsequent non-NVpr without an
         intervening call to BlendBarrierNV?

      RESOLVED:  We specify that a blend barrier is inserted prior to each
      cover primitives, so that cover primitives are blended coherently
      relative to geometry from previous primitives (cover or otherwise).  We
      do not guarantee that a blend barrier is inserted after each cover
      primitive, so applications need to call BlendBarrierNV manually if
      subsequent non-cover primitives are rendered to the same set of pixels.

    (32) On implementations supporting fully coherent blending, should we
         provide some mode allowing implementations to opt out of coherent
         blending?

      RESOLVED:  Yes.  We will provide an enable allowing applications to
      disable coherent blending in case where (a) implementations are able to
      provide higher-performance implementations if they don't have to worry
      about full coherence and/or ordering and (b) applications are willing to
      use BlendBarrierNV() to take advantage of the higher-performance
      implementation.  The enable will be on by default, which means that
      advanced blending on fully capable implementations will be "safe" unless
      explicitly disabled.

    (33) When fully coherent blending is disabled or not supported,
         BlendBarrierNV() is used to indicate boundaries between passes.
         Should any other commands in the OpenGL API also implicitly serve as
         blend barriers?

      RESOLVED:  In general, no.  Except for the NV_path_rendering case above,
      we will require applications manually use BlendBarrierNV().  There may
      be other operations that indirectly cause blend results to become
      coherent (in an implementation-dependent way), but we don't attempt to
      provide any explicit guarantees.  Except for path rendering cover
      primitives (see issues 30 and 31), applications should always call
      BlendBarrierNV() between possibly overlapping passes.

      Note that implementations of this extension may use texture mapping
      hardware to source the framebuffer for blending and may end up caching
      pre-blended texel values.  This can cause subsequent texture fetches to
      return stale values unless the texture is re-bound, the
      TextureBarrierNV() command from the NV_texture_barrier extension is
      used, or some other action is taken to break the "rendering feedback
      loop".  The existing spec already defines that texel fetches produce
      undefined results when a texture object is bound both as a texture and
      attached to the current draw framebuffer, with or without advanced blend
      equations.  See the "Rendering Feedback Loops" section (p. 316 in the
      OpenGL 4.1 Compatibility Profile specification) for more information.

    (34) How should the blend equations COLORDODGE_NV and COLORBURN_NV be
         expressed mathematically?

      RESOLVED:  We changed the definition of these equations after the
      NV_blend_equation_advanced spec was originally published, as discussed
      below.  These changes add new special cases to the COLORDODGE_NV and
      COLORBURN_NV equations that are found in newer compositing standard
      specifications and in a number of implementations of old and new
      standards.  We believe that the omission of the special case in other
      older specifications is a bug.  We have no plans to add new blend
      equation tokens to support "equivalent" modes without the new special
      case.

      Note, however, that older versions of this extension and older NVIDIA
      drivers implementing it will lack these special cases.  A driver update
      may be required to get the new behavior.
      
      There is some disagreement in different published specifications about
      how these two blend equations should be handled.  At the time this
      extension was initially developed, all specifications we found that
      specified blending equations mathematically (see issue 28) were written
      the same way.  Since then, we discovered that newer working drafts of
      the W3C Compositing and Blending Level 1 specification (for CSS and SVG)
      express "color-burn" as follows (translated to our nomenclature):

        if (Cd == 1)            // their Cb (backdrop) is our Cd (destination)
          f(Cs,Cd) = 1          // their B() is our f()
        else if (Cs == 0)
          f(Cs,Cd) = 0
        else
          f(Cs,Cd) = 1 - min(1, (1-Cd)/Cs)

      http://www.w3.org/TR/2013/WD-compositing-1-20131010/
        #blendingcolorburn

      Earlier versions of the same W3C specification, an older SVG compositing
      draft specification, the Adobe PDF specification (and the ISO 32000-1
      standard), and the KHR_advanced_blending extension to OpenVG all specify
      the following equation without the initial special case:

        if (Cs == 0)
          f(Cs,Cd) = 0
        else
          f(Cs,Cd) = 1 - min(1, (1-Cd)/Cs)

        http://www.w3.org/TR/2012/WD-compositing-20120816/
          #blendingcolorburn
        http://www.w3.org/TR/2011/WD-SVGCompositing-20110315/
        http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/
          pdfs/pdf_reference_1-7.pdf
        http://www.khronos.org/registry/vg/extensions/KHR/
          advanced_blending.txt

      For the Adobe PDF specification, the corrected blend equations are
      published in an Adobe supplement to ISO 32000-1 and are expected to be
      accepted in a future version of the standard:

        http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/
          devnet/pdf/pdfs/adobe_supplement_iso32000_1.pdf

      The author's understanding is that multiple shipping implementations of
      these blending modes implement the special case for "Cd==1" above,
      including various Adobe products and the open-source Ghostscript
      project.

      We believe that the extra special case in this specification is
      consistent with the physical model of color burning.  Burning is
      described in

        http://en.wikipedia.org/wiki/Dodging_and_burning

      as making a print with normal exposure, and then adding additional
      exposure to darken the overall image.  In the general equation:

        1 - min(1, (1-Cd)/Cs)

      Cs operates as a sort of fudge factor where a value of 1.0 implies no
      additional exposure time and 0.0 implies arbitrarily long additional
      exposure time, where the initial amount of exposure (1-Cd) is multiplied
      by 1/Cs and then clamped to maximum exposure by the min() operation.
      The Cd==1 special case here implies that we get zero exposure in the
      initial print, since 1-Cd==0.  No amount of extra exposure time will
      generate any additional exposure.  This would imply that the final
      result should have zero exposure and thus a final f() value of 1.  This
      matches the initial special case.  Without that special case, we would
      hit the second special case if Cs==0 (infinite exposure time), which
      would yield an incorrect final value of 0 (full exposure).

      A similar issue applies to COLORDODGE_NV, where some specifications
      include a special case for Cb==0 while others do not.  We have added a
      special case there as well.

Revision History
    
    Rev.    Date    Author    Changes
    ----  --------  --------  -----------------------------------------
     9    09/30/14  pbrown    Fix incorrectly specified color clamping in
                              the HSL blend modes.

     8    02/26/14  pbrown    For non-coherent blending, clarify that all
                              writes to a sample are considered to "touch"
                              that sample and require a BlendBarrierOES call
                              before blending overlapping geometry.  Clears,
                              non-blended geometry, and copies by
                              BlitFramebuffer or TexSubImage are all
                              considered to "touch" a sample (bug 11738).
                              Specify that non-premultiplied values
                              corresponding to ill-conditioned premultiplied
                              colors such as (1,1,1,0) are undefined (bug
                              11739).  Update issue (12) related to
                              ill-conditioned premultiplied colors.

     7    11/06/13  pbrown    Fix the language about non-coherent blending
                              to specify that results are undefined only if an
                              individual *sample* is touched more than once
                              (instead of *pixel*).  Minor language tweaks to
                              use "equations" consistently, instead of
                              sometimes using "modes".

     6    10/21/13  pbrown    Add NV-suffixed names for tokens reusing values
                              from core OpenGL enums (XOR, RED, GREEN, BLUE)
                              that are not in core OpenGL ES 2.0.  This allows
                              code targeting both APIs to use the same
                              NV-suffixed #defines.  Some older versions of
                              the OpenGL "glext.h" header will not have the
                              NV-suffixed names.

     5    10/21/13  pbrown    Add a reference to the Adobe supplement to
                              ISO 32000-1, which includes the corrected
                              equations for COLORDODGE_NV and COLORBURN_NV.
                              Move "NVIDIA Implementation Details" down
                              a bit in the spec.

     4    10/16/13  pbrown    Modify the definition of COLORDODGE_NV and
                              COLORBURN_NV to match de facto standard
                              implemenations and new CSS/SVG compositing
                              spec; add issue (34).

     3    08/19/13  pbrown    Fix typos in the OpenGL ES 2.0 and 3.0
                              interactions sections.

     2    07/25/13  mjk       Add W3C CSS compositing reference.

     1              pbrown    Internal revisions.
