blob: 2633cd4c5999e705742f414f495d5508822a8f30 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_Blend_DEFINED
#define skgpu_Blend_DEFINED
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/private/SkColorData.h"
#include "include/private/base/SkDebug.h"
#include <cstdint>
enum class SkBlendMode;
class SkString;
namespace skgpu {
/**
* Equations for alpha-blending.
*/
enum class BlendEquation : uint8_t {
// Basic blend equations.
kAdd, //<! Cs*S + Cd*D
kSubtract, //<! Cs*S - Cd*D
kReverseSubtract, //<! Cd*D - Cs*S
// Advanced blend equations. These are described in the SVG and PDF specs.
kScreen,
kOverlay,
kDarken,
kLighten,
kColorDodge,
kColorBurn,
kHardLight,
kSoftLight,
kDifference,
kExclusion,
kMultiply,
kHSLHue,
kHSLSaturation,
kHSLColor,
kHSLLuminosity,
kIllegal,
kFirstAdvanced = kScreen,
kLast = kIllegal,
};
static const int kBlendEquationCnt = static_cast<int>(BlendEquation::kLast) + 1;
/**
* Coefficients for alpha-blending.
*/
enum class BlendCoeff : uint8_t {
kZero, //<! 0
kOne, //<! 1
kSC, //<! src color
kISC, //<! one minus src color
kDC, //<! dst color
kIDC, //<! one minus dst color
kSA, //<! src alpha
kISA, //<! one minus src alpha
kDA, //<! dst alpha
kIDA, //<! one minus dst alpha
kConstC, //<! constant color
kIConstC, //<! one minus constant color
kS2C,
kIS2C,
kS2A,
kIS2A,
kIllegal,
kLast = kIllegal,
};
struct BlendInfo {
SkDEBUGCODE(SkString dump() const;)
bool operator==(const BlendInfo& other) const {
return fEquation == other.fEquation &&
fSrcBlend == other.fSrcBlend &&
fDstBlend == other.fDstBlend &&
fBlendConstant == other.fBlendConstant &&
fWritesColor == other.fWritesColor;
}
skgpu::BlendEquation fEquation = skgpu::BlendEquation::kAdd;
skgpu::BlendCoeff fSrcBlend = skgpu::BlendCoeff::kOne;
skgpu::BlendCoeff fDstBlend = skgpu::BlendCoeff::kZero;
SkPMColor4f fBlendConstant = SK_PMColor4fTRANSPARENT;
bool fWritesColor = true;
};
static const int kBlendCoeffCnt = static_cast<int>(BlendCoeff::kLast) + 1;
static constexpr bool BlendCoeffRefsSrc(const BlendCoeff coeff) {
return BlendCoeff::kSC == coeff || BlendCoeff::kISC == coeff || BlendCoeff::kSA == coeff ||
BlendCoeff::kISA == coeff;
}
static constexpr bool BlendCoeffRefsDst(const BlendCoeff coeff) {
return BlendCoeff::kDC == coeff || BlendCoeff::kIDC == coeff || BlendCoeff::kDA == coeff ||
BlendCoeff::kIDA == coeff;
}
static constexpr bool BlendCoeffRefsSrc2(const BlendCoeff coeff) {
return BlendCoeff::kS2C == coeff || BlendCoeff::kIS2C == coeff ||
BlendCoeff::kS2A == coeff || BlendCoeff::kIS2A == coeff;
}
static constexpr bool BlendCoeffsUseSrcColor(BlendCoeff srcCoeff, BlendCoeff dstCoeff) {
return BlendCoeff::kZero != srcCoeff || BlendCoeffRefsSrc(dstCoeff);
}
static constexpr bool BlendCoeffsUseDstColor(BlendCoeff srcCoeff,
BlendCoeff dstCoeff,
bool srcColorIsOpaque) {
return BlendCoeffRefsDst(srcCoeff) ||
(dstCoeff != BlendCoeff::kZero && !(dstCoeff == BlendCoeff::kISA && srcColorIsOpaque));
}
static constexpr bool BlendEquationIsAdvanced(BlendEquation equation) {
return equation >= BlendEquation::kFirstAdvanced &&
equation != BlendEquation::kIllegal;
}
static constexpr bool BlendModifiesDst(BlendEquation equation,
BlendCoeff srcCoeff,
BlendCoeff dstCoeff) {
return (BlendEquation::kAdd != equation && BlendEquation::kReverseSubtract != equation) ||
BlendCoeff::kZero != srcCoeff || BlendCoeff::kOne != dstCoeff;
}
static constexpr bool BlendCoeffRefsConstant(const BlendCoeff coeff) {
return coeff == BlendCoeff::kConstC || coeff == BlendCoeff::kIConstC;
}
static constexpr bool BlendShouldDisable(BlendEquation equation,
BlendCoeff srcCoeff,
BlendCoeff dstCoeff) {
return (BlendEquation::kAdd == equation || BlendEquation::kSubtract == equation) &&
BlendCoeff::kOne == srcCoeff && BlendCoeff::kZero == dstCoeff;
}
/**
* Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
*
* For "add" and "reverse subtract" the blend equation with f=coverage is:
*
* D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
* = f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
*
* (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the
* following relationship holds:
*
* (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
*
* (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.)
*
* It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff
* does not reference S). For the dst term, this will work as long as the following is true:
*|
* dstCoeff' == f * dstCoeff + (1 - f)
* dstCoeff' == 1 - f * (1 - dstCoeff)
*
* By inspection we can see this will work as long as dstCoeff has a 1, and any other term in
* dstCoeff references S.
*
* Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src
* color so folding in coverage is allowed.
*/
static constexpr bool BlendAllowsCoverageAsAlpha(BlendEquation equation,
BlendCoeff srcCoeff,
BlendCoeff dstCoeff) {
return BlendEquationIsAdvanced(equation) ||
!BlendModifiesDst(equation, srcCoeff, dstCoeff) ||
((BlendEquation::kAdd == equation || BlendEquation::kReverseSubtract == equation) &&
!BlendCoeffRefsSrc(srcCoeff) &&
(BlendCoeff::kOne == dstCoeff || BlendCoeff::kISC == dstCoeff ||
BlendCoeff::kISA == dstCoeff));
}
/**
* Returns the name of the SkSL built-in blend function for a SkBlendMode.
*/
const char* BlendFuncName(SkBlendMode mode);
/**
* If a blend can be represented by `blend_porter_duff`, returns the associated blend constants as
* an array of four floats. If not, returns an empty span.
*/
SkSpan<const float> GetPorterDuffBlendConstants(SkBlendMode mode);
/**
* Returns a pair of "blend function + uniform data" for a particular SkBlendMode.
* This allows us to use fewer unique functions when generating shaders, e.g. every Porter-Duff
* blend can use the same function.
*/
struct ReducedBlendModeInfo {
const char* fFunction;
SkSpan<const float> fUniformData;
};
ReducedBlendModeInfo GetReducedBlendModeInfo(SkBlendMode mode);
} // namespace skgpu
#endif // skgpu_Blend_DEFINED