Bug 950312 - Part 5: Implement SCREEN and MULTIPLY for CompositorOGL. r=mtseng

This commit is contained in:
Matt Woodrow 2014-05-09 22:06:18 +12:00
parent 5329b64309
commit dbd6f4096d
4 changed files with 88 additions and 18 deletions

View File

@ -803,7 +803,9 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
}
ShaderConfigOGL
CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
CompositorOGL::GetShaderConfigFor(Effect *aEffect,
MaskType aMask,
gfx::CompositionOp aOp) const
{
ShaderConfigOGL config;
@ -841,6 +843,12 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
source->GetFormat() == gfx::SurfaceFormat::R5G6B5);
config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
source->GetFormat());
if (aOp == gfx::CompositionOp::OP_MULTIPLY &&
!texturedEffect->mPremultiplied) {
// We can do these blend modes just using glBlendFunc but we need the data
// to be premultiplied first.
config.SetPremultiply(true);
}
break;
}
}
@ -886,6 +894,40 @@ CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect&
}
}
static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
{
if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
return false;
}
GLenum srcBlend;
GLenum dstBlend;
switch (aBlendMode) {
case gfx::CompositionOp::OP_OVER:
MOZ_ASSERT(!aIsPremultiplied);
srcBlend = LOCAL_GL_SRC_ALPHA;
dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
break;
case gfx::CompositionOp::OP_SCREEN:
srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA;
dstBlend = LOCAL_GL_ONE_MINUS_SRC_COLOR;
break;
case gfx::CompositionOp::OP_MULTIPLY:
// If the source data was un-premultiplied we should have already
// asked the fragment shader to fix that.
srcBlend = LOCAL_GL_DST_COLOR;
dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
break;
default:
MOZ_ASSERT(0, "Unsupported blend mode!");
}
aGL->fBlendFuncSeparate(srcBlend, dstBlend,
LOCAL_GL_ONE, LOCAL_GL_ONE);
return true;
}
void
CompositorOGL::DrawQuadInternal(const Rect& aRect,
const Rect& aClipRect,
@ -963,7 +1005,14 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
aOpacity = 1.f;
}
ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
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;
}
ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType, blendMode);
config.SetOpacity(aOpacity != 1.f);
ShaderProgramOGL *program = GetShaderProgramFor(config);
program->Activate();
@ -982,6 +1031,8 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
}
bool didSetBlendMode = false;
switch (aEffectChain.mPrimaryEffect->mType) {
case EffectTypes::SOLID_COLOR: {
program->SetRenderColor(color);
@ -990,6 +1041,8 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
}
didSetBlendMode = SetBlendMode(gl(), blendMode);
BindAndDrawQuad(program, aDrawMode);
}
break;
@ -999,10 +1052,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
TextureSource *source = texturedEffect->mTexture;
if (!texturedEffect->mPremultiplied) {
mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
}
didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
gfx::Filter filter = texturedEffect->mFilter;
gfx3DMatrix textureTransform;
@ -1030,11 +1080,6 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
BindAndDrawQuadWithTextureRect(program, textureTransform,
texturedEffect->mTextureCoords, source);
if (!texturedEffect->mPremultiplied) {
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
}
}
break;
case EffectTypes::YCBCR: {
@ -1060,6 +1105,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
if (maskType != MaskType::MaskNone) {
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
}
didSetBlendMode = SetBlendMode(gl(), blendMode);
BindAndDrawQuadWithTextureRect(program,
gfx3DMatrix(),
effectYCbCr->mTextureCoords,
@ -1096,11 +1142,13 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this. Pass true for the flip parameter to introduce a second flip
// that cancels the other one out.
didSetBlendMode = SetBlendMode(gl(), blendMode);
BindAndDrawQuad(program);
}
break;
case EffectTypes::COMPONENT_ALPHA: {
MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!");
EffectComponentAlpha* effectComponentAlpha =
static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
@ -1149,6 +1197,11 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
break;
}
if (didSetBlendMode) {
gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
}
// in case rendering has used some other GL context
MakeCurrent();
}

View File

@ -178,11 +178,15 @@ public:
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE
{
return TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
XRE_GetProcessType(),
GetMaxTextureSize(),
mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
SupportsPartialTextureUpdate());
TextureFactoryIdentifier result =
TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
XRE_GetProcessType(),
GetMaxTextureSize(),
mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
SupportsPartialTextureUpdate());
result.mSupportedBlendModes += gfx::CompositionOp::OP_SCREEN;
result.mSupportedBlendModes += gfx::CompositionOp::OP_MULTIPLY;
return result;
}
virtual TemporaryRef<CompositingRenderTarget>
@ -360,7 +364,9 @@ private:
gfx::Rect *aClipRectOut = nullptr,
gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
ShaderConfigOGL GetShaderConfigFor(Effect *aEffect, MaskType aMask = MaskType::MaskNone) const;
ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
MaskType aMask = MaskType::MaskNone,
gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER) const;
ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
/**

View File

@ -130,6 +130,12 @@ ShaderConfigOGL::SetMask3D(bool aEnabled)
SetFeature(ENABLE_MASK_3D, aEnabled);
}
void
ShaderConfigOGL::SetPremultiply(bool aEnabled)
{
SetFeature(ENABLE_PREMULTIPLY, aEnabled);
}
/* static */ ProgramProfileOGL
ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
{
@ -323,6 +329,9 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
if (aConfig.mFeatures & ENABLE_OPACITY) {
fs << " color *= uLayerOpacity;" << endl;
}
if (aConfig.mFeatures & ENABLE_PREMULTIPLY) {
fs << " color.rgb *= color.a;" << endl;
}
}
if (aConfig.mFeatures & ENABLE_MASK_3D) {
fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;

View File

@ -41,7 +41,8 @@ enum ShaderFeatures {
ENABLE_BLUR=0x100,
ENABLE_COLOR_MATRIX=0x200,
ENABLE_MASK_2D=0x400,
ENABLE_MASK_3D=0x800
ENABLE_MASK_3D=0x800,
ENABLE_PREMULTIPLY=0x1000
};
class KnownUniform {
@ -171,6 +172,7 @@ public:
void SetBlur(bool aEnabled);
void SetMask2D(bool aEnabled);
void SetMask3D(bool aEnabled);
void SetPremultiply(bool aEnabled);
bool operator< (const ShaderConfigOGL& other) const {
return mFeatures < other.mFeatures;