Bug 983574 - When setting a SourceSurface input on a FilterNodeD2D1, delay the conversion to ID2D1Image until the actual DrawFilter call. r=Bas

This commit is contained in:
Markus Stange 2014-09-25 15:18:29 -04:00
parent de564f5251
commit e02b56d697
4 changed files with 102 additions and 58 deletions

View File

@ -388,7 +388,10 @@ DrawTargetD2D::DrawFilter(FilterNode *aNode,
hr = rt->QueryInterface((ID2D1DeviceContext**)byRef(dc));
if (SUCCEEDED(hr)) {
dc->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
FilterNodeD2D1* node = static_cast<FilterNodeD2D1*>(aNode);
node->WillDraw(this);
dc->DrawImage(node->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
Rect destRect = aSourceRect;
destRect.MoveBy(aDestPoint);
@ -1320,7 +1323,7 @@ DrawTargetD2D::CreateFilter(FilterType aType)
HRESULT hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc));
if (SUCCEEDED(hr)) {
return FilterNodeD2D1::Create(this, dc, aType);
return FilterNodeD2D1::Create(dc, aType);
}
#endif
return FilterNodeSoftware::Create(aType);

View File

@ -155,7 +155,10 @@ DrawTargetD2D1::DrawFilter(FilterNode *aNode,
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
mDC->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
FilterNodeD2D1* node = static_cast<FilterNodeD2D1*>(aNode);
node->WillDraw(this);
mDC->DrawImage(node->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
}
@ -701,7 +704,7 @@ DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops,
TemporaryRef<FilterNode>
DrawTargetD2D1::CreateFilter(FilterType aType)
{
return FilterNodeD2D1::Create(this, mDC, aType);
return FilterNodeD2D1::Create(mDC, aType);
}
bool

View File

@ -523,10 +523,10 @@ static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
/* static */
TemporaryRef<FilterNode>
FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType)
FilterNodeD2D1::Create(ID2D1DeviceContext *aDC, FilterType aType)
{
if (aType == FilterType::CONVOLVE_MATRIX) {
return new FilterNodeConvolveD2D1(aDT, aDC);
return new FilterNodeConvolveD2D1(aDC);
}
RefPtr<ID2D1Effect> effect;
@ -544,9 +544,9 @@ FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aTyp
case FilterType::GAMMA_TRANSFER:
case FilterType::TABLE_TRANSFER:
case FilterType::DISCRETE_TRANSFER:
return new FilterNodeComponentTransferD2D1(aDT, aDC, effect, aType);
return new FilterNodeComponentTransferD2D1(aDC, effect, aType);
default:
return new FilterNodeD2D1(aDT, effect, aType);
return new FilterNodeD2D1(effect, aType);
}
}
@ -579,8 +579,23 @@ FilterNodeD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
}
}
RefPtr<ID2D1Image> image = GetImageForSourceSurface(mDT, aSurface);
effect->SetInput(input, image);
MOZ_ASSERT(input < effect->GetInputCount());
mInputSurfaces.resize(effect->GetInputCount());
mInputFilters.resize(effect->GetInputCount());
// In order to convert aSurface into an ID2D1Image, we need to know what
// DrawTarget we paint into. However, the same FilterNode object can be
// used on different DrawTargets, so we need to hold on to the SourceSurface
// objects and delay the conversion until we're actually painted and know
// our target DrawTarget.
// The conversion happens in WillDraw().
mInputSurfaces[input] = aSurface;
mInputFilters[input] = nullptr;
// Clear the existing image from the effect.
effect->SetInput(input, nullptr);
}
void
@ -599,15 +614,47 @@ FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
}
}
MOZ_ASSERT(input < effect->GetInputCount());
MOZ_ASSERT(input < effect->GetInputCount());
if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
gfxWarning() << "Unknown input SourceSurface set on effect.";
if (aFilter && aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
gfxWarning() << "Unknown input FilterNode set on effect.";
MOZ_ASSERT(0);
return;
}
effect->SetInputEffect(input, static_cast<FilterNodeD2D1*>(aFilter)->OutputEffect());
FilterNodeD2D1* filter = static_cast<FilterNodeD2D1*>(aFilter);
mInputSurfaces.resize(effect->GetInputCount());
mInputFilters.resize(effect->GetInputCount());
// We hold on to the FilterNode object so that we can call WillDraw() on it.
mInputSurfaces[input] = nullptr;
mInputFilters[input] = filter;
if (filter) {
effect->SetInputEffect(input, filter->OutputEffect());
}
}
void
FilterNodeD2D1::WillDraw(DrawTarget *aDT)
{
// Convert input SourceSurfaces into ID2D1Images and set them on the effect.
for (size_t inputIndex = 0; inputIndex < mInputSurfaces.size(); inputIndex++) {
if (mInputSurfaces[inputIndex]) {
ID2D1Effect* effect = InputEffect();
RefPtr<ID2D1Image> image = GetImageForSourceSurface(aDT, mInputSurfaces[inputIndex]);
effect->SetInput(inputIndex, image);
}
}
// Call WillDraw() on our input filters.
for (std::vector<RefPtr<FilterNodeD2D1>>::iterator it = mInputFilters.begin();
it != mInputFilters.end(); it++) {
if (*it) {
(*it)->WillDraw(aDT);
}
}
}
void
@ -771,8 +818,8 @@ FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
mEffect->SetValue(input, D2DMatrix(aMatrix));
}
FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC)
: FilterNodeD2D1(aDT, nullptr, FilterType::CONVOLVE_MATRIX)
FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(ID2D1DeviceContext *aDC)
: FilterNodeD2D1(nullptr, FilterType::CONVOLVE_MATRIX)
, mEdgeMode(EDGE_MODE_DUPLICATE)
{
// Correctly handling the interaction of edge mode and source rect is a bit
@ -845,31 +892,10 @@ FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceConte
UpdateSourceRect();
}
void
FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
{
MOZ_ASSERT(aIndex == 0);
mInput = GetImageForSourceSurface(mDT, aSurface);
mInputEffect = nullptr;
UpdateChain();
}
void
FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
{
MOZ_ASSERT(aIndex == 0);
if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
gfxWarning() << "Unknown input SourceSurface set on effect.";
MOZ_ASSERT(0);
return;
}
mInput = nullptr;
mInputEffect = static_cast<FilterNodeD2D1*>(aFilter)->mEffect;
FilterNodeD2D1::SetInput(aIndex, aFilter);
UpdateChain();
}
@ -886,6 +912,12 @@ FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
UpdateChain();
}
ID2D1Effect*
FilterNodeConvolveD2D1::InputEffect()
{
return mEdgeMode == EDGE_MODE_NONE ? mEffect.get() : mCompositeEffect.get();
}
void
FilterNodeConvolveD2D1::UpdateChain()
{
@ -897,19 +929,18 @@ FilterNodeConvolveD2D1::UpdateChain()
// EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
// input -------v
// flood --> composite --> crop --> border --> convolvematrix
//
// mEffect is convolvematrix.
ID2D1Effect *firstEffect = mCompositeEffect;
if (mEdgeMode == EDGE_MODE_NONE) {
firstEffect = mEffect;
} else {
if (mEdgeMode != EDGE_MODE_NONE) {
mEffect->SetInputEffect(0, mBorderEffect.get());
}
if (mInputEffect) {
firstEffect->SetInputEffect(0, mInputEffect);
} else {
firstEffect->SetInput(0, mInput);
RefPtr<ID2D1Effect> inputEffect;
if (mInputFilters.size() > 0 && mInputFilters[0]) {
inputEffect = mInputFilters[0]->OutputEffect();
}
InputEffect()->SetInputEffect(0, inputEffect);
if (mEdgeMode == EDGE_MODE_DUPLICATE) {
mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_CLAMP);
@ -980,9 +1011,9 @@ FilterNodeConvolveD2D1::UpdateSourceRect()
Float(mSourceRect.XMost()), Float(mSourceRect.YMost())));
}
FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC,
FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(ID2D1DeviceContext *aDC,
ID2D1Effect *aEffect, FilterType aType)
: FilterNodeD2D1(aDT, aEffect, aType)
: FilterNodeD2D1(aEffect, aType)
{
// D2D1 component transfer effects do strange things when it comes to
// premultiplication.

View File

@ -8,6 +8,7 @@
#include "2D.h"
#include "Filters.h"
#include <vector>
#include <d2d1_1.h>
#include <cguid.h>
@ -18,11 +19,10 @@ class FilterNodeD2D1 : public FilterNode
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeD2D1)
static TemporaryRef<FilterNode> Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType);
static TemporaryRef<FilterNode> Create(ID2D1DeviceContext *aDC, FilterType aType);
FilterNodeD2D1(DrawTarget* aDT, ID2D1Effect *aEffect, FilterType aType)
: mDT(aDT)
, mEffect(aEffect)
FilterNodeD2D1(ID2D1Effect *aEffect, FilterType aType)
: mEffect(aEffect)
, mType(aType)
{
InitUnmappedProperties();
@ -48,6 +48,12 @@ public:
virtual void SetAttribute(uint32_t aIndex, const IntPoint &aValue);
virtual void SetAttribute(uint32_t aIndex, const Matrix &aValue);
// Called by DrawTarget before it draws our OutputEffect, and recursively
// by the filter nodes that have this filter as one of their inputs. This
// gives us a chance to convert any input surfaces to the target format for
// the DrawTarget that we will draw to.
virtual void WillDraw(DrawTarget *aDT);
protected:
friend class DrawTargetD2D1;
friend class DrawTargetD2D;
@ -58,8 +64,9 @@ protected:
void InitUnmappedProperties();
RefPtr<DrawTarget> mDT;
RefPtr<ID2D1Effect> mEffect;
std::vector<RefPtr<FilterNodeD2D1>> mInputFilters;
std::vector<RefPtr<SourceSurface>> mInputSurfaces;
FilterType mType;
};
@ -67,9 +74,8 @@ class FilterNodeConvolveD2D1 : public FilterNodeD2D1
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeConvolveD2D1)
FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC);
FilterNodeConvolveD2D1(ID2D1DeviceContext *aDC);
virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface);
virtual void SetInput(uint32_t aIndex, FilterNode *aFilter);
virtual void SetAttribute(uint32_t aIndex, uint32_t aValue);
@ -77,13 +83,14 @@ public:
virtual void SetAttribute(uint32_t aIndex, const IntPoint &aValue);
virtual void SetAttribute(uint32_t aIndex, const IntRect &aValue);
protected:
virtual ID2D1Effect* InputEffect();
private:
void UpdateChain();
void UpdateOffset();
void UpdateSourceRect();
RefPtr<ID2D1Image> mInput;
RefPtr<ID2D1Effect> mInputEffect;
RefPtr<ID2D1Effect> mFloodEffect;
RefPtr<ID2D1Effect> mCompositeEffect;
RefPtr<ID2D1Effect> mCropEffect;
@ -98,7 +105,7 @@ class FilterNodeComponentTransferD2D1 : public FilterNodeD2D1
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeComponentTransferD2D1)
FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC, ID2D1Effect *aEffect, FilterType aType);
FilterNodeComponentTransferD2D1(ID2D1DeviceContext *aDC, ID2D1Effect *aEffect, FilterType aType);
protected:
virtual ID2D1Effect* InputEffect() MOZ_OVERRIDE { return mPrePremultiplyEffect.get(); }