NV_blend_equation_advanced

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:         February 14, 2018
NVIDIA Revision:            10

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.  The HSL blend equations are only well defined
when the values of the input color components are in the range [0..1].
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)*(1-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.

(35) For "HSL" blend equations, the blend equation involves a clipping
     step where colors may be "clipped" if the blend would produce
     components are outside the range [0,1]. Are there inputs where this
     blend could produce ill-defined or nonsensical results?
     
  RESOLVED: Yes, the results of HSL blend equations are undefined if the
  input colors have components outside the range [0,1]. Even if the input
  colors are in-range, the basic color adjustment done in these blends
  could produce result components outside the range [0,1]. To compensate,
  the ClipColor() function in the specification interpolates the result
  color and a greyscale value that matches the luminance of the result.
  The math for the clipping operation assumes the luminance of the result
  color is in the range [0,1]. If that isn't the case, the clipping
  operation could result in a divide by zero (when all result components
  have the same out-of-bounds value) or perform an otherwise nonsensical
  computation.

Revision History

Rev.    Date    Author    Changes
----  --------  --------  ----------------------------------------------
10    02/14/18  pdaniell  Fix ClipColor() equation where in the
                          "if (maxcol > 1.0)" body the "(color-lum)*lum"
                          term should have been "(color-lum)*(1-lum)".
                          Also add new issue 35 for the case where the
                          inputs to SetLum() are outside the range
                          [0..1] and could cause a divide-by-zero in
                          ClipColor().

 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.