mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Add full mix-blend mode support to the OpenGL compositor. (bug 1235995 part 1, r=mstange)
This commit is contained in:
parent
8fcc59449e
commit
cf1d101569
@ -558,6 +558,31 @@ size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
|
||||
decomposedRectArrayT* aLayerRects,
|
||||
decomposedRectArrayT* aTextureRects);
|
||||
|
||||
static inline bool
|
||||
BlendOpIsMixBlendMode(gfx::CompositionOp aOp)
|
||||
{
|
||||
switch (aOp) {
|
||||
case gfx::CompositionOp::OP_MULTIPLY:
|
||||
case gfx::CompositionOp::OP_SCREEN:
|
||||
case gfx::CompositionOp::OP_OVERLAY:
|
||||
case gfx::CompositionOp::OP_DARKEN:
|
||||
case gfx::CompositionOp::OP_LIGHTEN:
|
||||
case gfx::CompositionOp::OP_COLOR_DODGE:
|
||||
case gfx::CompositionOp::OP_COLOR_BURN:
|
||||
case gfx::CompositionOp::OP_HARD_LIGHT:
|
||||
case gfx::CompositionOp::OP_SOFT_LIGHT:
|
||||
case gfx::CompositionOp::OP_DIFFERENCE:
|
||||
case gfx::CompositionOp::OP_EXCLUSION:
|
||||
case gfx::CompositionOp::OP_HUE:
|
||||
case gfx::CompositionOp::OP_SATURATION:
|
||||
case gfx::CompositionOp::OP_COLOR:
|
||||
case gfx::CompositionOp::OP_LUMINOSITY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -71,6 +71,18 @@ BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
|
||||
aProgram->SetMaskLayerTransform(aTransform);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit)
|
||||
{
|
||||
MOZ_ASSERT(aBackdrop);
|
||||
|
||||
mGLContext->fActiveTexture(aTexUnit);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop);
|
||||
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
|
||||
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
|
||||
aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
|
||||
int aSurfaceHeight, bool aUseExternalSurfaceSize)
|
||||
: mWidget(aWidget)
|
||||
@ -707,9 +719,16 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
|
||||
GLuint aSourceFrameBuffer,
|
||||
GLuint *aFBO, GLuint *aTexture)
|
||||
{
|
||||
*aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer);
|
||||
mGLContext->fGenFramebuffers(1, aFBO);
|
||||
}
|
||||
|
||||
GLuint
|
||||
CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource, GLuint aSourceFrameBuffer)
|
||||
{
|
||||
// we're about to create a framebuffer backed by textures to use as an intermediate
|
||||
// surface. What to do if its size (as given by aRect) would exceed the
|
||||
@ -722,7 +741,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
clampedRect.width = std::min(clampedRect.width, maxTexSize);
|
||||
clampedRect.height = std::min(clampedRect.height, maxTexSize);
|
||||
|
||||
GLuint tex, fbo;
|
||||
GLuint tex;
|
||||
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGLContext->fGenTextures(1, &tex);
|
||||
@ -774,6 +793,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
buf.get());
|
||||
}
|
||||
|
||||
GLenum error = mGLContext->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
nsAutoCString msg;
|
||||
@ -801,10 +821,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mGLContext->fBindTexture(mFBOTextureTarget, 0);
|
||||
|
||||
mGLContext->fGenFramebuffers(1, &fbo);
|
||||
|
||||
*aFBO = fbo;
|
||||
*aTexture = tex;
|
||||
return tex;
|
||||
}
|
||||
|
||||
ShaderConfigOGL
|
||||
@ -855,6 +872,9 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect,
|
||||
source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16);
|
||||
config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
|
||||
source->GetFormat());
|
||||
if (!texturedEffect->mPremultiplied) {
|
||||
config.SetNoPremultipliedAlpha();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -862,6 +882,7 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect,
|
||||
config.SetMask2D(aMask == MaskType::Mask2d);
|
||||
config.SetMask3D(aMask == MaskType::Mask3d);
|
||||
config.SetDEAA(aDEAAEnabled);
|
||||
config.SetCompositionOp(aOp);
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -898,10 +919,15 @@ CompositorOGL::ResetProgram()
|
||||
mCurrentProgram = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
|
||||
{
|
||||
if (BlendOpIsMixBlendMode(aBlendMode)) {
|
||||
// Mix-blend modes require an extra step (or more) that cannot be expressed
|
||||
// in the fixed-function blending capabilities of opengl. We handle them
|
||||
// separately in shaders, and the shaders assume we will use our default
|
||||
// blend function for compositing (premultiplied OP_OVER).
|
||||
return false;
|
||||
}
|
||||
if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
|
||||
return false;
|
||||
}
|
||||
@ -1066,11 +1092,18 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
aOpacity = 1.f;
|
||||
}
|
||||
|
||||
GLuint mixBlendBackdrop = 0;
|
||||
gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
|
||||
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
|
||||
EffectBlendMode *blendEffect =
|
||||
static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
|
||||
blendMode = blendEffect->mBlendMode;
|
||||
if (BlendOpIsMixBlendMode(blendMode)) {
|
||||
gfx::IntRect rect(gfx::IntPoint(0, 0), mCurrentRenderTarget->GetSize());
|
||||
|
||||
mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
|
||||
}
|
||||
}
|
||||
|
||||
// Only apply DEAA to quads that have been transformed such that aliasing
|
||||
@ -1184,6 +1217,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
if (maskType != MaskType::MaskNone) {
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
|
||||
}
|
||||
|
||||
didSetBlendMode = SetBlendMode(gl(), blendMode);
|
||||
|
||||
@ -1221,6 +1257,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
if (maskType != MaskType::MaskNone) {
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
|
||||
}
|
||||
|
||||
BindAndDrawQuadWithTextureRect(program, aRect, texturedEffect->mTextureCoords, source);
|
||||
}
|
||||
@ -1249,6 +1288,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
if (maskType != MaskType::MaskNone) {
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
|
||||
}
|
||||
didSetBlendMode = SetBlendMode(gl(), blendMode);
|
||||
BindAndDrawQuadWithTextureRect(program,
|
||||
aRect,
|
||||
@ -1283,6 +1325,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
if (maskType != MaskType::MaskNone) {
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
|
||||
}
|
||||
didSetBlendMode = SetBlendMode(gl(), blendMode);
|
||||
BindAndDrawQuadWithTextureRect(program,
|
||||
aRect,
|
||||
@ -1309,6 +1354,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
if (maskType != MaskType::MaskNone) {
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
|
||||
}
|
||||
|
||||
if (config.mFeatures & ENABLE_TEXTURE_RECT) {
|
||||
// 2DRect case, get the multiplier right for a sampler2DRect
|
||||
@ -1392,6 +1440,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
|
||||
LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
if (mixBlendBackdrop) {
|
||||
gl()->fDeleteTextures(1, &mixBlendBackdrop);
|
||||
}
|
||||
|
||||
// in case rendering has used some other GL context
|
||||
MakeCurrent();
|
||||
@ -1451,22 +1502,12 @@ CompositorOGL::EndFrame()
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Unbind all textures
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
for (GLuint i = 0; i <= 4; i++) {
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,6 +216,11 @@ public:
|
||||
mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
|
||||
SupportsPartialTextureUpdate());
|
||||
result.mSupportedBlendModes += gfx::CompositionOp::OP_SOURCE;
|
||||
for (uint8_t op = 0; op < uint8_t(gfx::CompositionOp::OP_COUNT); op++) {
|
||||
if (BlendOpIsMixBlendMode(gfx::CompositionOp(op))) {
|
||||
result.mSupportedBlendModes += gfx::CompositionOp(op);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -422,6 +427,7 @@ private:
|
||||
void CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
|
||||
GLuint aSourceFrameBuffer,
|
||||
GLuint *aFBO, GLuint *aTexture);
|
||||
GLuint CreateTexture(const gfx::IntRect& aRect, bool aCopyFromSource, GLuint aSourceFrameBuffer);
|
||||
|
||||
void BindAndDrawQuads(ShaderProgramOGL *aProg,
|
||||
int aQuads,
|
||||
@ -445,6 +451,12 @@ private:
|
||||
void ActivateProgram(ShaderProgramOGL *aProg);
|
||||
void CleanupResources();
|
||||
|
||||
/**
|
||||
* Bind the texture behind the current render target as the backdrop for a
|
||||
* mix-blend shader.
|
||||
*/
|
||||
void BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit);
|
||||
|
||||
/**
|
||||
* Copies the content of our backbuffer to the set transaction target.
|
||||
* Does not restore the target FBO, so only call from EndFrame.
|
||||
|
@ -43,6 +43,7 @@ AddUniforms(ProgramProfileOGL& aProfile)
|
||||
"uBlackTexture",
|
||||
"uWhiteTexture",
|
||||
"uMaskTexture",
|
||||
"uBackdropTexture",
|
||||
"uRenderColor",
|
||||
"uTexCoordMultiplier",
|
||||
"uCbCrTexCoordMultiplier",
|
||||
@ -148,9 +149,9 @@ ShaderConfigOGL::SetMask3D(bool aEnabled)
|
||||
}
|
||||
|
||||
void
|
||||
ShaderConfigOGL::SetPremultiply(bool aEnabled)
|
||||
ShaderConfigOGL::SetNoPremultipliedAlpha()
|
||||
{
|
||||
SetFeature(ENABLE_PREMULTIPLY, aEnabled);
|
||||
SetFeature(ENABLE_NO_PREMUL_ALPHA, true);
|
||||
}
|
||||
|
||||
void
|
||||
@ -159,6 +160,12 @@ ShaderConfigOGL::SetDEAA(bool aEnabled)
|
||||
SetFeature(ENABLE_DEAA, aEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
ShaderConfigOGL::SetCompositionOp(CompositionOp aOp)
|
||||
{
|
||||
mCompositionOp = aOp;
|
||||
}
|
||||
|
||||
/* static */ ProgramProfileOGL
|
||||
ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
{
|
||||
@ -167,6 +174,8 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
|
||||
AddUniforms(result);
|
||||
|
||||
CompositionOp blendOp = aConfig.mCompositionOp;
|
||||
|
||||
vs << "#ifdef GL_ES" << endl;
|
||||
vs << "#define EDGE_PRECISION mediump" << endl;
|
||||
vs << "#else" << endl;
|
||||
@ -190,6 +199,10 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
vs << "varying vec2 vTexCoord;" << endl;
|
||||
}
|
||||
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
vs << "varying vec2 vBackdropCoord;" << endl;
|
||||
}
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
vs << "uniform mat4 uMaskTransform;" << endl;
|
||||
@ -273,6 +286,10 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
}
|
||||
vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
|
||||
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
// Move from clip space coordinates into texture/uv-coordinates.
|
||||
vs << " vBackdropCoord = (finalPosition.xy + vec2(1.0, 1.0)) / 2.0;" << endl;
|
||||
}
|
||||
vs << " gl_Position = finalPosition;" << endl;
|
||||
vs << "}" << endl;
|
||||
|
||||
@ -309,6 +326,9 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
|
||||
}
|
||||
}
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
fs << "varying vec2 vBackdropCoord;" << endl;
|
||||
}
|
||||
|
||||
const char *sampler2D = "sampler2D";
|
||||
const char *texture2D = "texture2D";
|
||||
@ -342,6 +362,13 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
fs << "uniform " << sampler2D << " uTexture;" << endl;
|
||||
}
|
||||
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
// Component alpha should be flattened away inside blend containers.
|
||||
MOZ_ASSERT(!(aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA));
|
||||
|
||||
fs << "uniform sampler2D uBackdropTexture;" << endl;
|
||||
}
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
fs << "varying vec3 vMaskCoord;" << endl;
|
||||
@ -352,6 +379,10 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
fs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
|
||||
}
|
||||
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
BuildMixBlender(aConfig, fs);
|
||||
}
|
||||
|
||||
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
|
||||
fs << "vec4 sample(vec2 coord) {" << endl;
|
||||
fs << " vec4 color;" << endl;
|
||||
@ -459,9 +490,6 @@ For [0,1] instead of [0,255], and to 5 places:
|
||||
if (aConfig.mFeatures & ENABLE_OPACITY) {
|
||||
fs << " color *= uLayerOpacity;" << endl;
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_PREMULTIPLY) {
|
||||
fs << " color.rgb *= color.a;" << endl;
|
||||
}
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_DEAA) {
|
||||
// Calculate the sub-pixel coverage of the pixel and modulate its opacity
|
||||
@ -473,6 +501,10 @@ For [0,1] instead of [0,255], and to 5 places:
|
||||
fs << " deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
|
||||
fs << " color *= deaaCoverage;" << endl;
|
||||
}
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
fs << " vec4 backdrop = texture2D(uBackdropTexture, vBackdropCoord);" << endl;
|
||||
fs << " color = mixAndBlend(backdrop, color);" << endl;
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
|
||||
fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;
|
||||
@ -507,10 +539,226 @@ For [0,1] instead of [0,255], and to 5 places:
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
result.mTextureCount = 1;
|
||||
}
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
result.mTextureCount += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
ProgramProfileOGL::BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs)
|
||||
{
|
||||
// From the "Compositing and Blending Level 1" spec.
|
||||
// Generate helper functions first.
|
||||
switch (aConfig.mCompositionOp) {
|
||||
case gfx::CompositionOp::OP_OVERLAY:
|
||||
case gfx::CompositionOp::OP_HARD_LIGHT:
|
||||
// Note: we substitute (2*src-1) into the screen formula below.
|
||||
fs << "float hardlight(float dest, float src) {" << endl;
|
||||
fs << " if (src <= 0.5) {" << endl;
|
||||
fs << " return dest * (2.0 * src);" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " return 2.0*dest + 2.0*src - 1.0 - 2.0*dest*src;" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << "}" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_COLOR_DODGE:
|
||||
fs << "float dodge(float dest, float src) {" << endl;
|
||||
fs << " if (dest == 0.0) {" << endl;
|
||||
fs << " return 0.0;" << endl;
|
||||
fs << " } else if (src == 1.0) {" << endl;
|
||||
fs << " return 1.0;" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " return min(1.0, dest / (1.0 - src));" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << "}" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_COLOR_BURN:
|
||||
fs << "float burn(float dest, float src) {" << endl;
|
||||
fs << " if (dest == 1.0) {" << endl;
|
||||
fs << " return 1.0;" << endl;
|
||||
fs << " } else if (src == 0.0) {" << endl;
|
||||
fs << " return 0.0;" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " return 1.0 - min(1.0, (1.0 - dest) / src);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << "}" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_SOFT_LIGHT:
|
||||
fs << "float darken(float dest) {" << endl;
|
||||
fs << " if (dest <= 0.25) {" << endl;
|
||||
fs << " return ((16.0 * dest - 12.0) * dest + 4.0) * dest;" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " return sqrt(dest);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << "}" << endl;
|
||||
fs << "float softlight(float dest, float src) {" << endl;
|
||||
fs << " if (src <= 0.5) {" << endl;
|
||||
fs << " return dest - (1.0 - 2.0 * src) * dest * (1.0 - dest);" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " return dest + (2.0 * src - 1.0) * (darken(dest) - dest);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << "}" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_HUE:
|
||||
case gfx::CompositionOp::OP_SATURATION:
|
||||
case gfx::CompositionOp::OP_COLOR:
|
||||
case gfx::CompositionOp::OP_LUMINOSITY:
|
||||
fs << "float Lum(vec3 c) {" << endl;
|
||||
fs << " return dot(vec3(0.3, 0.59, 0.11), c);" << endl;
|
||||
fs << "}" << endl;
|
||||
fs << "vec3 ClipColor(vec3 c) {" << endl;
|
||||
fs << " float L = Lum(c);" << endl;
|
||||
fs << " float n = min(min(c.r, c.g), c.b);" << endl;
|
||||
fs << " float x = max(max(c.r, c.g), c.b);" << endl;
|
||||
fs << " if (n < 0.0) {" << endl;
|
||||
fs << " c = L + (((c - L) * L) / (L - n));" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " if (x > 1.0) {" << endl;
|
||||
fs << " c = L + (((c - L) * (1.0 - L)) / (x - L));" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " return c;" << endl;
|
||||
fs << "}" << endl;
|
||||
fs << "vec3 SetLum(vec3 c, float L) {" << endl;
|
||||
fs << " float d = L - Lum(c);" << endl;
|
||||
fs << " return ClipColor(vec3(" << endl;
|
||||
fs << " c.r + d," << endl;
|
||||
fs << " c.g + d," << endl;
|
||||
fs << " c.b + d));" << endl;
|
||||
fs << "}" << endl;
|
||||
fs << "float Sat(vec3 c) {" << endl;
|
||||
fs << " return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b);" << endl;
|
||||
fs << "}" << endl;
|
||||
|
||||
// To use this helper, re-arrange rgb such that r=min, g=mid, and b=max.
|
||||
fs << "vec3 SetSatInner(vec3 c, float s) {" << endl;
|
||||
fs << " if (c.b > c.r) {" << endl;
|
||||
fs << " c.g = (((c.g - c.r) * s) / (c.b - c.r));" << endl;
|
||||
fs << " c.b = s;" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " c.gb = vec2(0.0, 0.0);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " return vec3(0.0, c.gb);" << endl;
|
||||
fs << "}" << endl;
|
||||
|
||||
fs << "vec3 SetSat(vec3 c, float s) {" << endl;
|
||||
fs << " if (c.r <= c.g) {" << endl;
|
||||
fs << " if (c.g <= c.b) {" << endl;
|
||||
fs << " c.rgb = SetSatInner(c.rgb, s);" << endl;
|
||||
fs << " } else if (c.r <= c.b) {" << endl;
|
||||
fs << " c.rbg = SetSatInner(c.rbg, s);" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " c.brg = SetSatInner(c.brg, s);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " } else if (c.r <= c.b) {" << endl;
|
||||
fs << " c.grb = SetSatInner(c.grb, s);" << endl;
|
||||
fs << " } else if (c.g <= c.b) {" << endl;
|
||||
fs << " c.gbr = SetSatInner(c.gbr, s);" << endl;
|
||||
fs << " } else {" << endl;
|
||||
fs << " c.bgr = SetSatInner(c.bgr, s);" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " return c;" << endl;
|
||||
fs << "}" << endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate the main blending helper.
|
||||
fs << "vec3 blend(vec3 dest, vec3 src) {" << endl;
|
||||
switch (aConfig.mCompositionOp) {
|
||||
case gfx::CompositionOp::OP_MULTIPLY:
|
||||
fs << " return dest * src;" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_SCREEN:
|
||||
fs << " return dest + src - (dest * src);" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_OVERLAY:
|
||||
fs << " return vec3(" << endl;
|
||||
fs << " hardlight(src.r, dest.r)," << endl;
|
||||
fs << " hardlight(src.g, dest.g)," << endl;
|
||||
fs << " hardlight(src.b, dest.b));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_DARKEN:
|
||||
fs << " return min(dest, src);" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_LIGHTEN:
|
||||
fs << " return max(dest, src);" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_COLOR_DODGE:
|
||||
fs << " return vec3(" << endl;
|
||||
fs << " dodge(dest.r, src.r)," << endl;
|
||||
fs << " dodge(dest.g, src.g)," << endl;
|
||||
fs << " dodge(dest.b, src.b));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_COLOR_BURN:
|
||||
fs << " return vec3(" << endl;
|
||||
fs << " burn(dest.r, src.r)," << endl;
|
||||
fs << " burn(dest.g, src.g)," << endl;
|
||||
fs << " burn(dest.b, src.b));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_HARD_LIGHT:
|
||||
fs << " return vec3(" << endl;
|
||||
fs << " hardlight(dest.r, src.r)," << endl;
|
||||
fs << " hardlight(dest.g, src.g)," << endl;
|
||||
fs << " hardlight(dest.b, src.b));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_SOFT_LIGHT:
|
||||
fs << " return vec3(" << endl;
|
||||
fs << " softlight(dest.r, src.r)," << endl;
|
||||
fs << " softlight(dest.g, src.g)," << endl;
|
||||
fs << " softlight(dest.b, src.b));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_DIFFERENCE:
|
||||
fs << " return abs(dest - src);" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_EXCLUSION:
|
||||
fs << " return dest + src - 2.0*dest*src;" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_HUE:
|
||||
fs << " return SetLum(SetSat(src, Sat(dest)), Lum(dest));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_SATURATION:
|
||||
fs << " return SetLum(SetSat(dest, Sat(src)), Lum(dest));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_COLOR:
|
||||
fs << " return SetLum(src, Lum(dest));" << endl;
|
||||
break;
|
||||
case gfx::CompositionOp::OP_LUMINOSITY:
|
||||
fs << " return SetLum(dest, Lum(src));" << endl;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unknown blend mode");
|
||||
}
|
||||
fs << "}" << endl;
|
||||
|
||||
// Generate the mix-blend function the fragment shader will call.
|
||||
fs << "vec4 mixAndBlend(vec4 backdrop, vec4 color) {" << endl;
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// Infinity into the blend function and return incorrect results.
|
||||
fs << " if (backdrop.a == 0.0) {" << endl;
|
||||
fs << " return color;" << endl;
|
||||
fs << " }" << endl;
|
||||
fs << " if (color.a == 0.0) {" << endl;
|
||||
fs << " return backdrop;" << endl;
|
||||
fs << " }" << endl;
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop is always
|
||||
// premultiplied, so undo the premultiply. If the source is premultiplied we
|
||||
// must fix that as well.
|
||||
fs << " backdrop.rgb /= backdrop.a;" << endl;
|
||||
if (!(aConfig.mFeatures & ENABLE_NO_PREMUL_ALPHA)) {
|
||||
fs << " color.rgb /= color.a;" << endl;
|
||||
}
|
||||
fs << " vec3 blended = blend(backdrop.rgb, color.rgb);" << endl;
|
||||
fs << " color.rgb = (1.0 - backdrop.a) * color.rgb + backdrop.a * blended.rgb;" << endl;
|
||||
fs << " color.rgb *= color.a;" << endl;
|
||||
fs << " return color;" << endl;
|
||||
fs << "}" << endl;
|
||||
}
|
||||
|
||||
ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile)
|
||||
: mGL(aGL)
|
||||
, mProgram(0)
|
||||
|
@ -39,7 +39,7 @@ enum ShaderFeatures {
|
||||
ENABLE_COLOR_MATRIX=0x400,
|
||||
ENABLE_MASK_2D=0x800,
|
||||
ENABLE_MASK_3D=0x1000,
|
||||
ENABLE_PREMULTIPLY=0x2000,
|
||||
ENABLE_NO_PREMUL_ALPHA=0x2000,
|
||||
ENABLE_DEAA=0x4000
|
||||
};
|
||||
|
||||
@ -65,6 +65,7 @@ public:
|
||||
BlackTexture,
|
||||
WhiteTexture,
|
||||
MaskTexture,
|
||||
BackdropTexture,
|
||||
RenderColor,
|
||||
TexCoordMultiplier,
|
||||
CbCrTexCoordMultiplier,
|
||||
@ -207,7 +208,9 @@ class ShaderConfigOGL
|
||||
{
|
||||
public:
|
||||
ShaderConfigOGL() :
|
||||
mFeatures(0) {}
|
||||
mFeatures(0),
|
||||
mCompositionOp(gfx::CompositionOp::OP_OVER)
|
||||
{}
|
||||
|
||||
void SetRenderColor(bool aEnabled);
|
||||
void SetTextureTarget(GLenum aTarget);
|
||||
@ -221,11 +224,14 @@ public:
|
||||
void SetBlur(bool aEnabled);
|
||||
void SetMask2D(bool aEnabled);
|
||||
void SetMask3D(bool aEnabled);
|
||||
void SetPremultiply(bool aEnabled);
|
||||
void SetDEAA(bool aEnabled);
|
||||
void SetCompositionOp(gfx::CompositionOp aOp);
|
||||
void SetNoPremultipliedAlpha();
|
||||
|
||||
bool operator< (const ShaderConfigOGL& other) const {
|
||||
return mFeatures < other.mFeatures;
|
||||
return mFeatures < other.mFeatures ||
|
||||
(mFeatures == other.mFeatures &&
|
||||
(int)mCompositionOp < (int)other.mCompositionOp);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -237,6 +243,7 @@ public:
|
||||
}
|
||||
|
||||
int mFeatures;
|
||||
gfx::CompositionOp mCompositionOp;
|
||||
};
|
||||
|
||||
static inline ShaderConfigOGL
|
||||
@ -278,6 +285,9 @@ struct ProgramProfileOGL
|
||||
ProgramProfileOGL() :
|
||||
mTextureCount(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
static void BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs);
|
||||
};
|
||||
|
||||
|
||||
@ -433,6 +443,10 @@ public:
|
||||
SetUniform(KnownUniform::MaskTexture, aUnit);
|
||||
}
|
||||
|
||||
void SetBackdropTextureUnit(GLint aUnit) {
|
||||
SetUniform(KnownUniform::BackdropTexture, aUnit);
|
||||
}
|
||||
|
||||
void SetRenderColor(const gfx::Color& aColor) {
|
||||
SetUniform(KnownUniform::RenderColor, aColor);
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<style>
|
||||
.parent {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
isolation: isolate;
|
||||
}
|
||||
.child {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: #7775b6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="parent">
|
||||
<div class="child">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
25
layout/reftests/css-blending/mix-blend-mode-soft-light.html
Normal file
25
layout/reftests/css-blending/mix-blend-mode-soft-light.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<style>
|
||||
.parent {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
isolation: isolate;
|
||||
background: #5856a2;
|
||||
}
|
||||
.child {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
mix-blend-mode: soft-light;
|
||||
opacity: 0.5;
|
||||
background: white;
|
||||
will-change: opacity;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="parent">
|
||||
<div class="child">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
@ -43,7 +43,7 @@ fuzzy(64,37) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-9520
|
||||
pref(layout.css.mix-blend-mode.enabled,true) pref(layout.css.filters.enabled,true) == mix-blend-mode-and-filter.html mix-blend-mode-and-filter-ref.html
|
||||
pref(layout.css.mix-blend-mode.enabled,true) pref(layout.css.filters.enabled,true) == mix-blend-mode-and-filter.svg mix-blend-mode-and-filter-ref.svg
|
||||
|
||||
pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(d2d,1,14400) == mix-blend-mode-child-of-blended-has-opacity.html mix-blend-mode-child-of-blended-has-opacity-ref.html
|
||||
fuzzy(1,14400) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-child-of-blended-has-opacity.html mix-blend-mode-child-of-blended-has-opacity-ref.html
|
||||
|
||||
pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-nested-976533.html mix-blend-mode-nested-976533-ref.html
|
||||
pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-culling-1207041.html mix-blend-mode-culling-1207041-ref.html
|
||||
@ -86,9 +86,11 @@ pref(layout.css.background-blend-mode.enabled,true) == background-blending-backg
|
||||
pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html
|
||||
|
||||
pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html
|
||||
fuzzy-if(Android,4,768) pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html
|
||||
fuzzy-if(Android,4,768) fuzzy-if(gtkWidget,1,132) pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html
|
||||
|
||||
pref(layout.css.background-blend-mode.enabled,true) == background-blending-moz-element.html background-blending-moz-element-ref.html
|
||||
|
||||
fuzzy(1,40000) pref(layout.css.background-blend-mode.enabled,true) == mix-blend-mode-soft-light.html mix-blend-mode-soft-light-ref.html
|
||||
|
||||
# Test plan 4.4.2 element with isolation:isolate creates an isolated group for blended children
|
||||
pref(layout.css.isolation.enabled,true) == blend-isolation.html blend-isolation-ref.html
|
||||
|
Loading…
Reference in New Issue
Block a user