Bug 1422475: Create FilterNodes on the paint thread when using Direct2D. r=dvander
MozReview-Commit-ID: 9hlcf8SZNWZ
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -9,16 +9,17 @@
#include <math.h>
#include "2D.h"
#include "Blur.h"
#include "Filters.h"
#include <vector>
#include "CaptureCommandList.h"
+#include "FilterNodeCapture.h"
namespace mozilla {
namespace gfx {
enum class CommandType : int8_t {
DRAWSURFACE = 0,
DRAWFILTER,
DRAWSURFACEWITHSHADOW,
@@ -241,17 +242,21 @@ public:
}
void CloneInto(CaptureCommandList* aList) {
CLONE_INTO(DrawFilterCommand)(mFilter, mSourceRect, mDestPoint, mOptions);
}
virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
{
- aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions);
+ FilterNode* filter = mFilter.get();
+ if (mFilter->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
+ filter = static_cast<FilterNodeCapture*>(filter)->Validate(aDT);
+ }
+ aDT->DrawFilter(filter, mSourceRect, mDestPoint, mOptions);
}
static const bool AffectsSnapshot = true;
private:
RefPtr<FilterNode> mFilter;
Rect mSourceRect;
Point mDestPoint;
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DrawTargetCapture.h"
#include "DrawCommand.h"
#include "gfxPlatform.h"
#include "SourceSurfaceCapture.h"
+#include "FilterNodeCapture.h"
namespace mozilla {
namespace gfx {
DrawTargetCaptureImpl::~DrawTargetCaptureImpl()
{
if (mSnapshot && !mSnapshot->hasOneRef()) {
@@ -413,10 +414,20 @@ DrawTargetCaptureImpl::CreateSimilarDraw
RefPtr<DrawTarget>
DrawTargetCaptureImpl::CreateSimilarRasterTarget(const IntSize& aSize, SurfaceFormat aFormat) const
{
MOZ_ASSERT(!mRefDT->IsCaptureDT());
return mRefDT->CreateSimilarDrawTarget(aSize, aFormat);
}
+already_AddRefed<FilterNode>
+DrawTargetCaptureImpl::CreateFilter(FilterType aType)
+{
+ if (mRefDT->GetBackendType() == BackendType::DIRECT2D1_1) {
+ return MakeRefPtr<FilterNodeCapture>(aType).forget();
+ } else {
+ return mRefDT->CreateFilter(aType);
+ }
+}
+
} // namespace gfx
} // namespace mozilla
--- a/gfx/2d/DrawTargetCapture.h
+++ b/gfx/2d/DrawTargetCapture.h
@@ -138,20 +138,17 @@ public:
virtual already_AddRefed<GradientStops>
CreateGradientStops(GradientStop *aStops,
uint32_t aNumStops,
ExtendMode aExtendMode = ExtendMode::CLAMP) const override
{
return mRefDT->CreateGradientStops(aStops, aNumStops, aExtendMode);
}
- virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override
- {
- return mRefDT->CreateFilter(aType);
- }
+ virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
void ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform);
bool ContainsOnlyColoredGlyphs(RefPtr<ScaledFont>& aScaledFont, Color& aColor, std::vector<Glyph>& aGlyphs) override;
protected:
virtual ~DrawTargetCaptureImpl();
new file mode 100644
--- /dev/null
+++ b/gfx/2d/FilterNodeCapture.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FilterNodeCapture.h"
+
+namespace mozilla {
+namespace gfx {
+
+struct Setter
+{
+ Setter(FilterNode* aNode, DrawTarget* aDT, bool aInputsChanged)
+ : mNode{aNode}, mIndex{0}, mDT{aDT}, mInputsChanged{aInputsChanged} {}
+ template<typename T>
+ void match(T& aValue) { mNode->SetAttribute(mIndex, aValue); }
+
+ FilterNode* mNode;
+ uint32_t mIndex;
+ DrawTarget* mDT;
+ bool mInputsChanged;
+};
+
+template<>
+void
+Setter::match<std::vector<Float>>(std::vector<Float>& aValue)
+{
+ mNode->SetAttribute(mIndex, aValue.data(), aValue.size());
+}
+
+template<>
+void
+Setter::match<RefPtr<SourceSurface>>(RefPtr<SourceSurface>& aSurface)
+{
+ if (!mInputsChanged) {
+ return;
+ }
+ mNode->SetInput(mIndex, aSurface);
+}
+
+template<>
+void
+Setter::match<RefPtr<FilterNode>>(RefPtr<FilterNode>& aNode)
+{
+ FilterNode* node = aNode;
+ if (node->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
+ FilterNodeCapture* captureNode = static_cast<FilterNodeCapture*>(node);
+ node = captureNode->Validate(mDT);
+ }
+ if (!mInputsChanged) {
+ return;
+ }
+
+ mNode->SetInput(mIndex, node);
+}
+
+FilterNode*
+FilterNodeCapture::Validate(DrawTarget* aDT)
+{
+ if (!mFilterNodeInternal) {
+ mFilterNodeInternal = aDT->CreateFilter(mType);
+ }
+
+ if (!mFilterNodeInternal) {
+ return nullptr;
+ }
+
+ Setter setter(mFilterNodeInternal, aDT, mInputsChanged);
+
+ for (auto attribute : mAttributes)
+ {
+ setter.mIndex = attribute.first;
+ // Variant's matching doesn't seem to compile to terribly efficient code,
+ // this is probably fine since this happens on the paint thread, if ever
+ // needed it would be fairly simple to write something more optimized.
+ attribute.second.match(setter);
+ }
+ mAttributes.clear();
+
+ for (auto input : mInputs) {
+ setter.mIndex = input.first;
+ input.second.match(setter);
+ }
+ mInputsChanged = false;
+
+ return mFilterNodeInternal.get();
+}
+
+void
+FilterNodeCapture::SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize)
+{
+ std::vector<Float> vec(aSize);
+ memcpy(vec.data(), aValues, sizeof(Float) * aSize);
+ AttributeValue att(std::move(vec));
+ auto result = mAttributes.insert({ aIndex, att });
+ if (!result.second) {
+ result.first->second = att;
+ }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/FilterNodeCapture.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_FILTERNODECAPTURE_H_
+#define MOZILLA_GFX_FILTERNODECAPTURE_H_
+
+#include "2D.h"
+#include "Filters.h"
+#include <unordered_map>
+#include <vector>
+#include "mozilla/Variant.h"
+
+namespace mozilla {
+namespace gfx {
+
+class FilterNodeCapture final : public FilterNode
+{
+public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeCapture)
+
+ explicit FilterNodeCapture(FilterType aType)
+ : mType{aType}
+ , mInputsChanged{true}
+ {
+ }
+
+ virtual FilterBackend GetBackendType() override { return FILTER_BACKEND_CAPTURE; }
+
+ FilterNode* Validate(DrawTarget* aDT);
+
+ template<typename T, typename C>
+ void Replace(uint32_t aIndex, T& aValue, C& aContainer)
+ {
+ // This replace function avoids generating the hash twice.
+ auto result = aContainer.insert({ aIndex, C::value_type::second_type{aValue} });
+ if (!result.second) {
+ result.first->second = C::value_type::second_type{aValue};
+ }
+ }
+
+ virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) override
+ {
+ mInputsChanged = true;
+ Replace(aIndex, RefPtr<SourceSurface>{aSurface}, mInputs);
+ }
+ virtual void SetInput(uint32_t aIndex, FilterNode *aFilter) override
+ {
+ mInputsChanged = true;
+ Replace(aIndex, RefPtr<FilterNode>{aFilter}, mInputs);
+ }
+
+ using AttributeValue = Variant<
+ uint32_t,
+ Float,
+ Point,
+ Matrix5x4,
+ Point3D,
+ Size,
+ IntSize,
+ Color,
+ Rect,
+ IntRect,
+ bool,
+ std::vector<Float>,
+ IntPoint,
+ Matrix
+ >;
+
+ virtual void SetAttribute(uint32_t aIndex, uint32_t aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, Float aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Point &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Point3D &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Size &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const IntSize &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Color &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Rect &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const IntRect &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, bool aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize) override;
+ virtual void SetAttribute(uint32_t aIndex, const IntPoint &aValue) override { Replace(aIndex, aValue, mAttributes); }
+ virtual void SetAttribute(uint32_t aIndex, const Matrix &aValue) override { Replace(aIndex, aValue, mAttributes); }
+
+private:
+ FilterType mType;
+ RefPtr<FilterNode> mFilterNodeInternal;
+
+ // This only contains attributes that were set since the last validation.
+ std::unordered_map<uint32_t, AttributeValue> mAttributes;
+
+ // This always contains all inputs, so that Validate may be called on input
+ // filter nodes.
+ std::unordered_map<uint32_t, Variant<RefPtr<SourceSurface>, RefPtr<FilterNode>>> mInputs;
+
+ // This is true if SetInput was called since the last validation.
+ bool mInputsChanged;
+};
+
+}
+}
+
+#endif
--- a/gfx/2d/Filters.h
+++ b/gfx/2d/Filters.h
@@ -17,17 +17,18 @@
namespace mozilla {
namespace gfx {
class SourceSurface;
enum FilterBackend {
FILTER_BACKEND_SOFTWARE = 0,
FILTER_BACKEND_DIRECT2D1_1,
- FILTER_BACKEND_RECORDING
+ FILTER_BACKEND_RECORDING,
+ FILTER_BACKEND_CAPTURE
};
enum TransformFilterAtts
{
ATT_TRANSFORM_MATRIX = 0, // Matrix
ATT_TRANSFORM_FILTER // Filter
};
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -162,16 +162,17 @@ UNIFIED_SOURCES += [
'DrawingJob.cpp',
'DrawTarget.cpp',
'DrawTargetCairo.cpp',
'DrawTargetCapture.cpp',
'DrawTargetDual.cpp',
'DrawTargetRecording.cpp',
'DrawTargetTiled.cpp',
'DrawTargetWrapAndRecord.cpp',
+ 'FilterNodeCapture.cpp',
'FilterNodeSoftware.cpp',
'FilterProcessing.cpp',
'FilterProcessingScalar.cpp',
'ImageScaling.cpp',
'JobScheduler.cpp',
'Matrix.cpp',
'Path.cpp',
'PathCairo.cpp',
--- a/layout/reftests/bugs/961887-2.html
+++ b/layout/reftests/bugs/961887-2.html
@@ -1,9 +1,9 @@
-<!DOCTYPE html>
+<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Make sure that we don't pull background colors into container layers that have effects applied on them</title>
<style>
#outer {
background-color: white;