1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef MOZILLA_GFX_DRAWTARGETD2D1_H_
8 #define MOZILLA_GFX_DRAWTARGETD2D1_H_
9 
10 #include "2D.h"
11 #include <d3d11.h>
12 #include <d2d1_1.h>
13 #include "PathD2D.h"
14 #include "HelpersD2D.h"
15 #include "mozilla/StaticPtr.h"
16 
17 #include <vector>
18 #include <sstream>
19 
20 #include <unordered_set>
21 
22 struct IDWriteFactory;
23 
24 namespace mozilla {
25 namespace gfx {
26 
27 class SourceSurfaceD2D1;
28 
29 const int32_t kLayerCacheSize1 = 5;
30 
31 class DrawTargetD2D1 : public DrawTarget {
32  public:
33   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D1, override)
34   DrawTargetD2D1();
35   virtual ~DrawTargetD2D1();
36 
37   virtual bool IsValid() const override;
GetType()38   virtual DrawTargetType GetType() const override {
39     return DrawTargetType::HARDWARE_RASTER;
40   }
GetBackendType()41   virtual BackendType GetBackendType() const override {
42     return BackendType::DIRECT2D1_1;
43   }
44   virtual already_AddRefed<SourceSurface> Snapshot() override;
45   virtual already_AddRefed<SourceSurface> IntoLuminanceSource(
46       LuminanceType aLuminanceType, float aOpacity) override;
GetSize()47   virtual IntSize GetSize() const override { return mSize; }
48 
49   virtual void Flush() override;
50   virtual void DrawSurface(SourceSurface* aSurface, const Rect& aDest,
51                            const Rect& aSource,
52                            const DrawSurfaceOptions& aSurfOptions,
53                            const DrawOptions& aOptions) override;
54   virtual void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
55                           const Point& aDestPoint,
56                           const DrawOptions& aOptions = DrawOptions()) override;
57   virtual void DrawSurfaceWithShadow(SourceSurface* aSurface,
58                                      const Point& aDest,
59                                      const DeviceColor& aColor,
60                                      const Point& aOffset, Float aSigma,
61                                      CompositionOp aOperator) override;
62   virtual void ClearRect(const Rect& aRect) override;
63   virtual void MaskSurface(
64       const Pattern& aSource, SourceSurface* aMask, Point aOffset,
65       const DrawOptions& aOptions = DrawOptions()) override;
66 
67   virtual void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
68                            const IntPoint& aDestination) override;
69 
70   virtual void FillRect(const Rect& aRect, const Pattern& aPattern,
71                         const DrawOptions& aOptions = DrawOptions()) override;
72   virtual void FillRoundedRect(
73       const RoundedRect& aRect, const Pattern& aPattern,
74       const DrawOptions& aOptions = DrawOptions()) override;
75 
76   virtual void StrokeRect(const Rect& aRect, const Pattern& aPattern,
77                           const StrokeOptions& aStrokeOptions = StrokeOptions(),
78                           const DrawOptions& aOptions = DrawOptions()) override;
79   virtual void StrokeLine(const Point& aStart, const Point& aEnd,
80                           const Pattern& aPattern,
81                           const StrokeOptions& aStrokeOptions = StrokeOptions(),
82                           const DrawOptions& aOptions = DrawOptions()) override;
83   virtual void Stroke(const Path* aPath, const Pattern& aPattern,
84                       const StrokeOptions& aStrokeOptions = StrokeOptions(),
85                       const DrawOptions& aOptions = DrawOptions()) override;
86   virtual void Fill(const Path* aPath, const Pattern& aPattern,
87                     const DrawOptions& aOptions = DrawOptions()) override;
88   virtual void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
89                           const Pattern& aPattern,
90                           const DrawOptions& aOptions = DrawOptions()) override;
91   virtual void Mask(const Pattern& aSource, const Pattern& aMask,
92                     const DrawOptions& aOptions = DrawOptions()) override;
93   virtual void PushClip(const Path* aPath) override;
94   virtual void PushClipRect(const Rect& aRect) override;
95   virtual void PushDeviceSpaceClipRects(const IntRect* aRects,
96                                         uint32_t aCount) override;
97 
98   virtual void PopClip() override;
99   virtual void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
100                          const Matrix& aMaskTransform,
101                          const IntRect& aBounds = IntRect(),
102                          bool aCopyBackground = false) override;
103   virtual void PopLayer() override;
104 
105   virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(
106       unsigned char* aData, const IntSize& aSize, int32_t aStride,
107       SurfaceFormat aFormat) const override;
108   virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(
109       SourceSurface* aSurface) const override;
110 
CreateSourceSurfaceFromNativeSurface(const NativeSurface & aSurface)111   virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
112       const NativeSurface& aSurface) const override {
113     return nullptr;
114   }
115 
116   virtual already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
117       const IntSize& aSize, SurfaceFormat aFormat) const override;
118   virtual bool CanCreateSimilarDrawTarget(const IntSize& aSize,
119                                           SurfaceFormat aFormat) const override;
120   virtual RefPtr<DrawTarget> CreateClippedDrawTarget(
121       const Rect& aBounds, SurfaceFormat aFormat) override;
122 
123   virtual already_AddRefed<PathBuilder> CreatePathBuilder(
124       FillRule aFillRule = FillRule::FILL_WINDING) const override;
125 
126   virtual already_AddRefed<GradientStops> CreateGradientStops(
127       GradientStop* aStops, uint32_t aNumStops,
128       ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
129 
130   virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
131 
SupportsRegionClipping()132   virtual bool SupportsRegionClipping() const override { return false; }
IsCurrentGroupOpaque()133   virtual bool IsCurrentGroupOpaque() override {
134     return CurrentLayer().mIsOpaque;
135   }
136 
GetNativeSurface(NativeSurfaceType aType)137   virtual void* GetNativeSurface(NativeSurfaceType aType) override {
138     return nullptr;
139   }
140 
DetachAllSnapshots()141   virtual void DetachAllSnapshots() override { MarkChanged(); }
142 
143   bool Init(const IntSize& aSize, SurfaceFormat aFormat);
144   bool Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat);
145   uint32_t GetByteSize() const;
146 
147   // This function will get an image for a surface, it may adjust the source
148   // transform for any transformation of the resulting image relative to the
149   // oritingal SourceSurface. By default, the surface and its transform are
150   // interpreted in user-space, but may be specified in device-space instead.
151   already_AddRefed<ID2D1Image> GetImageForSurface(
152       SourceSurface* aSurface, Matrix& aSourceTransform, ExtendMode aExtendMode,
153       const IntRect* aSourceRect = nullptr, bool aUserSpace = true);
154 
GetImageForSurface(SourceSurface * aSurface,ExtendMode aExtendMode)155   already_AddRefed<ID2D1Image> GetImageForSurface(SourceSurface* aSurface,
156                                                   ExtendMode aExtendMode) {
157     Matrix mat;
158     return GetImageForSurface(aSurface, mat, aExtendMode, nullptr);
159   }
160 
161   static RefPtr<ID2D1Factory1> factory();
162   static void CleanupD2D();
163 
string()164   operator std::string() const {
165     std::stringstream stream;
166     stream << "DrawTargetD2D 1.1 (" << this << ")";
167     return stream.str();
168   }
169 
GetMaxSurfaceSize()170   static uint32_t GetMaxSurfaceSize() {
171     return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
172   }
173 
174   static uint64_t mVRAMUsageDT;
175   static uint64_t mVRAMUsageSS;
176 
177  private:
178   friend class SourceSurfaceD2D1;
179 
180   void FlushInternal(bool aHasDependencyMutex = false);
181   bool EnsureInitialized();
182 
183   typedef std::unordered_set<DrawTargetD2D1*> TargetSet;
184 
185   // This function will mark the surface as changing, and make sure any
186   // copy-on-write snapshots are notified.
187   void MarkChanged();
188   bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp,
189                                          const Pattern& aPattern,
190                                          bool aClipIsComplex);
191   bool PrepareForDrawing(CompositionOp aOp, const Pattern& aPattern);
192   void FinalizeDrawing(CompositionOp aOp, const Pattern& aPattern);
FlushTransformToDC()193   void FlushTransformToDC() {
194     if (mTransformDirty) {
195       mDC->SetTransform(D2DMatrix(mTransform));
196       mTransformDirty = false;
197     }
198   }
199   void AddDependencyOnSource(SourceSurfaceD2D1* aSource);
200 
201   // Must be called with all clips popped and an identity matrix set.
202   already_AddRefed<ID2D1Image> GetImageForLayerContent(
203       bool aShouldPreserveContent = true);
204 
CurrentTarget()205   ID2D1Image* CurrentTarget() {
206     if (CurrentLayer().mCurrentList) {
207       return CurrentLayer().mCurrentList;
208     }
209     return mBitmap;
210   }
211 
212   // This returns the clipped geometry, in addition it returns aClipBounds which
213   // represents the intersection of all pixel-aligned rectangular clips that
214   // are currently set. The returned clipped geometry must be clipped by these
215   // bounds to correctly reflect the total clip. This is in device space and
216   // only for clips applied to the -current layer-.
217   already_AddRefed<ID2D1Geometry> GetClippedGeometry(IntRect* aClipBounds);
218 
219   already_AddRefed<ID2D1Geometry> GetInverseClippedGeometry();
220 
221   // This gives the device space clip rect applied to the -current layer-.
222   bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned);
223 
224   void PopAllClips();
225   void PushAllClips();
226   void PushClipsToDC(ID2D1DeviceContext* aDC, bool aForceIgnoreAlpha = false,
227                      const D2D1_RECT_F& aMaxRect = D2D1::InfiniteRect());
228   void PopClipsFromDC(ID2D1DeviceContext* aDC);
229 
230   already_AddRefed<ID2D1Brush> CreateTransparentBlackBrush();
231   already_AddRefed<ID2D1SolidColorBrush> GetSolidColorBrush(
232       const D2D_COLOR_F& aColor);
233   already_AddRefed<ID2D1Brush> CreateBrushForPattern(const Pattern& aPattern,
234                                                      Float aAlpha = 1.0f);
235 
236   void PushClipGeometry(ID2D1Geometry* aGeometry,
237                         const D2D1_MATRIX_3X2_F& aTransform,
238                         bool aPixelAligned = false);
239 
240   void PushD2DLayer(ID2D1DeviceContext* aDC, ID2D1Geometry* aGeometry,
241                     const D2D1_MATRIX_3X2_F& aTransform,
242                     bool aPixelAligned = false, bool aForceIgnoreAlpha = false,
243                     const D2D1_RECT_F& aLayerRect = D2D1::InfiniteRect());
244 
245   // This function is used to determine if the mDC is still valid; if it is
246   // stale, we should avoid using it to execute any draw commands.
247   bool IsDeviceContextValid() const;
248 
249   IntSize mSize;
250 
251   RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
252   // This is only valid if mCurrentClippedGeometry is non-null. And will
253   // only be the intersection of all pixel-aligned retangular clips. This is in
254   // device space.
255   IntRect mCurrentClipBounds;
256   mutable RefPtr<ID2D1DeviceContext> mDC;
257   RefPtr<ID2D1Bitmap1> mBitmap;
258   RefPtr<ID2D1CommandList> mCommandList;
259 
260   RefPtr<ID2D1SolidColorBrush> mSolidColorBrush;
261 
262   // We store this to prevent excessive SetTextRenderingParams calls.
263   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
264 
265   // List of pushed clips.
266   struct PushedClip {
267     D2D1_RECT_F mBounds;
268     // If mGeometry is non-null, the mTransform member will be used.
269     D2D1_MATRIX_3X2_F mTransform;
270     RefPtr<ID2D1Geometry> mGeometry;
271     // Indicates if mBounds, and when non-null, mGeometry with mTransform
272     // applied, are pixel-aligned.
273     bool mIsPixelAligned;
274   };
275 
276   // List of pushed layers.
277   struct PushedLayer {
PushedLayerPushedLayer278     PushedLayer()
279         : mClipsArePushed(false),
280           mIsOpaque(false),
281           mOldPermitSubpixelAA(false) {}
282 
283     std::vector<PushedClip> mPushedClips;
284     RefPtr<ID2D1CommandList> mCurrentList;
285     // True if the current clip stack is pushed to the CurrentTarget().
286     bool mClipsArePushed;
287     bool mIsOpaque;
288     bool mOldPermitSubpixelAA;
289   };
290   std::vector<PushedLayer> mPushedLayers;
CurrentLayer()291   PushedLayer& CurrentLayer() { return mPushedLayers.back(); }
292 
293   // The latest snapshot of this surface. This needs to be told when this
294   // target is modified. We keep it alive as a cache.
295   RefPtr<SourceSurfaceD2D1> mSnapshot;
296   std::shared_ptr<Mutex> mSnapshotLock;
297   // A list of targets we need to flush when we're modified.
298   TargetSet mDependentTargets;
299   // A list of targets which have this object in their mDependentTargets set
300   TargetSet mDependingOnTargets;
301 
302   uint32_t mUsedCommandListsSincePurge;
303   uint32_t mTransformedGlyphsSinceLastPurge;
304   // When a BlendEffect has been drawn to a command list, and that command list
305   // is subsequently used -again- as an input to a blend effect for a command
306   // list, this causes an infinite recursion inside D2D as it tries to resolve
307   // the bounds. If we resolve the current command list before this happens we
308   // can avoid the subsequent hang. (See bug 1293586)
309   uint32_t mComplexBlendsWithListInList;
310 
311   static StaticRefPtr<ID2D1Factory1> mFactory;
312   // This value is uesed to verify if the DrawTarget is created by a stale
313   // device.
314   uint32_t mDeviceSeq;
315 
316   // List of effects we use
317   bool EnsureLuminanceEffect();
318   RefPtr<ID2D1Effect> mLuminanceEffect;
319 
320   enum class InitState { Uninitialized, Success, Failure };
321   InitState mInitState;
322   RefPtr<IDXGISurface> mSurface;
323 };
324 
325 }  // namespace gfx
326 }  // namespace mozilla
327 
328 #endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */
329