mesa: Add draw time validation for advanced blending modes.
[mesa.git] / src / mesa / main / blend.c
index f07552b47789adf304df2c5c11d762a0c4369968..de6d3c48e05fd452e5e9811cf3f4d17cd6670317 100644 (file)
@@ -336,11 +336,11 @@ _mesa_BlendFuncSeparateiARB(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
 
 
 /**
- * Check if given blend equation is legal.
- * \return GL_TRUE if legal, GL_FALSE otherwise.
+ * Return true if \p mode is a legal blending equation, excluding
+ * GL_KHR_blend_equation_advanced modes.
  */
-static GLboolean
-legal_blend_equation(const struct gl_context *ctx, GLenum mode)
+static bool
+legal_simple_blend_equation(const struct gl_context *ctx, GLenum mode)
 {
    switch (mode) {
    case GL_FUNC_ADD:
@@ -355,6 +355,57 @@ legal_blend_equation(const struct gl_context *ctx, GLenum mode)
    }
 }
 
+static enum gl_advanced_blend_mode
+advanced_blend_mode_from_gl_enum(GLenum mode)
+{
+   switch (mode) {
+   case GL_MULTIPLY_KHR:
+      return BLEND_MULTIPLY;
+   case GL_SCREEN_KHR:
+      return BLEND_SCREEN;
+   case GL_OVERLAY_KHR:
+      return BLEND_OVERLAY;
+   case GL_DARKEN_KHR:
+      return BLEND_DARKEN;
+   case GL_LIGHTEN_KHR:
+      return BLEND_LIGHTEN;
+   case GL_COLORDODGE_KHR:
+      return BLEND_COLORDODGE;
+   case GL_COLORBURN_KHR:
+      return BLEND_COLORBURN;
+   case GL_HARDLIGHT_KHR:
+      return BLEND_HARDLIGHT;
+   case GL_SOFTLIGHT_KHR:
+      return BLEND_SOFTLIGHT;
+   case GL_DIFFERENCE_KHR:
+      return BLEND_DIFFERENCE;
+   case GL_EXCLUSION_KHR:
+      return BLEND_EXCLUSION;
+   case GL_HSL_HUE_KHR:
+      return BLEND_HSL_HUE;
+   case GL_HSL_SATURATION_KHR:
+      return BLEND_HSL_SATURATION;
+   case GL_HSL_COLOR_KHR:
+      return BLEND_HSL_COLOR;
+   case GL_HSL_LUMINOSITY_KHR:
+      return BLEND_HSL_LUMINOSITY;
+   default:
+      return BLEND_NONE;
+   }
+}
+
+/**
+ * If \p mode is one of the advanced blending equations defined by
+ * GL_KHR_blend_equation_advanced (and the extension is supported),
+ * return the corresponding BLEND_* enum.  Otherwise, return BLEND_NONE
+ * (which can also be treated as false).
+ */
+static enum gl_advanced_blend_mode
+advanced_blend_mode(const struct gl_context *ctx, GLenum mode)
+{
+   return _mesa_has_KHR_blend_equation_advanced(ctx) ?
+          advanced_blend_mode_from_gl_enum(mode) : BLEND_NONE;
+}
 
 /* This is really an extension function! */
 void GLAPIENTRY
@@ -364,6 +415,7 @@ _mesa_BlendEquation( GLenum mode )
    const unsigned numBuffers = num_buffers(ctx);
    unsigned buf;
    bool changed = false;
+   enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode);
 
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glBlendEquation(%s)\n",
@@ -390,7 +442,8 @@ _mesa_BlendEquation( GLenum mode )
    if (!changed)
       return;
 
-   if (!legal_blend_equation(ctx, mode)) {
+
+   if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
       return;
    }
@@ -402,9 +455,10 @@ _mesa_BlendEquation( GLenum mode )
       ctx->Color.Blend[buf].EquationA = mode;
    }
    ctx->Color._BlendEquationPerBuffer = GL_FALSE;
+   ctx->Color._AdvancedBlendMode = advanced_mode;
 
    if (ctx->Driver.BlendEquationSeparate)
-      (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode );
+      ctx->Driver.BlendEquationSeparate(ctx, mode, mode);
 }
 
 
@@ -415,6 +469,7 @@ void GLAPIENTRY
 _mesa_BlendEquationiARB(GLuint buf, GLenum mode)
 {
    GET_CURRENT_CONTEXT(ctx);
+   enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode);
 
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n",
@@ -426,7 +481,7 @@ _mesa_BlendEquationiARB(GLuint buf, GLenum mode)
       return;
    }
 
-   if (!legal_blend_equation(ctx, mode)) {
+   if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi");
       return;
    }
@@ -439,6 +494,9 @@ _mesa_BlendEquationiARB(GLuint buf, GLenum mode)
    ctx->Color.Blend[buf].EquationRGB = mode;
    ctx->Color.Blend[buf].EquationA = mode;
    ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+
+   if (buf == 0)
+      ctx->Color._AdvancedBlendMode = advanced_mode;
 }
 
 
@@ -482,12 +540,18 @@ _mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA )
       return;
    }
 
-   if (!legal_blend_equation(ctx, modeRGB)) {
+   /* Only allow simple blending equations.
+    * The GL_KHR_blend_equation_advanced spec says:
+    *
+    *    "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha>
+    *     parameters of BlendEquationSeparate or BlendEquationSeparatei."
+    */
+   if (!legal_simple_blend_equation(ctx, modeRGB)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)");
       return;
    }
 
-   if (!legal_blend_equation(ctx, modeA)) {
+   if (!legal_simple_blend_equation(ctx, modeA)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)");
       return;
    }
@@ -499,6 +563,7 @@ _mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA )
       ctx->Color.Blend[buf].EquationA = modeA;
    }
    ctx->Color._BlendEquationPerBuffer = GL_FALSE;
+   ctx->Color._AdvancedBlendMode = BLEND_NONE;
 
    if (ctx->Driver.BlendEquationSeparate)
       ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA);
@@ -524,12 +589,18 @@ _mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA)
       return;
    }
 
-   if (!legal_blend_equation(ctx, modeRGB)) {
+   /* Only allow simple blending equations.
+    * The GL_KHR_blend_equation_advanced spec says:
+    *
+    *    "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha>
+    *     parameters of BlendEquationSeparate or BlendEquationSeparatei."
+    */
+   if (!legal_simple_blend_equation(ctx, modeRGB)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)");
       return;
    }
 
-   if (!legal_blend_equation(ctx, modeA)) {
+   if (!legal_simple_blend_equation(ctx, modeA)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)");
       return;
    }
@@ -542,6 +613,7 @@ _mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA)
    ctx->Color.Blend[buf].EquationRGB = modeRGB;
    ctx->Color.Blend[buf].EquationA = modeA;
    ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+   ctx->Color._AdvancedBlendMode = BLEND_NONE;
 }
 
 
@@ -582,7 +654,7 @@ _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
    ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F);
 
    if (ctx->Driver.BlendColor)
-      (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor);
+      ctx->Driver.BlendColor(ctx, ctx->Color.BlendColor);
 }