Bug 1422475: Create FilterNodes on the paint thread when using Direct2D. r=dvander
authorBas Schouten <bschouten@mozilla.com>
Thu, 07 Dec 2017 03:21:49 +0100
changeset 447243 441bb5af46ac8c5d51a620343d29ed18ccd0dc45
parent 447242 c5fced4aa8fd5bb49c1ea78c752ccd7509b73cc6
child 447244 5115d6bc9009a84b76baa971b5ee35dc990c3838
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1422475
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1422475: Create FilterNodes on the paint thread when using Direct2D. r=dvander MozReview-Commit-ID: tt9pRshj6i
gfx/2d/DrawCommand.h
gfx/2d/DrawTargetCapture.cpp
gfx/2d/DrawTargetCapture.h
gfx/2d/FilterNodeCapture.cpp
gfx/2d/FilterNodeCapture.h
gfx/2d/Filters.h
gfx/2d/moz.build
--- 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);
+    RefPtr<FilterNode> filter = mFilter;
+    if (mFilter->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
+      filter = static_cast<FilterNodeCapture*>(filter.get())->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)
+{
+  RefPtr<FilterNode> node = aNode;
+  if (node->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
+    FilterNodeCapture* captureNode = static_cast<FilterNodeCapture*>(node.get());
+    node = captureNode->Validate(mDT);
+  }
+  if (!mInputsChanged) {
+    return;
+  }
+
+  mNode->SetInput(mIndex, node);
+}
+
+RefPtr<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, override)
+
+  explicit FilterNodeCapture(FilterType aType)
+    : mType{aType}
+    , mInputsChanged{true}
+  {
+  }
+
+  virtual FilterBackend GetBackendType() override { return FILTER_BACKEND_CAPTURE; }
+
+  RefPtr<FilterNode> Validate(DrawTarget* aDT);
+
+  template<typename T, typename C>
+  void Replace(uint32_t aIndex, const T& aValue, C& aContainer)
+  {
+    // This replace function avoids generating the hash twice.
+    auto result = aContainer.insert({ aIndex, typename C::mapped_type(aValue) });
+    if (!result.second) {
+      result.first->second = typename C::mapped_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',