1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_PROVIDER_H_
6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_PROVIDER_H_
7 
8 #include "cc/paint/skia_paint_canvas.h"
9 #include "cc/raster/playback_image_provider.h"
10 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
11 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
12 #include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
13 #include "third_party/skia/include/core/SkSurface.h"
14 
15 class GrContext;
16 
17 namespace cc {
18 class ImageDecodeCache;
19 class PaintCanvas;
20 }  // namespace cc
21 
22 namespace gpu {
23 namespace gles2 {
24 
25 class GLES2Interface;
26 
27 }  // namespace gles2
28 
29 namespace raster {
30 
31 class RasterInterface;
32 
33 }  // namespace raster
34 }  // namespace gpu
35 
36 namespace blink {
37 
38 class CanvasResourceDispatcher;
39 class WebGraphicsContext3DProviderWrapper;
40 
41 // CanvasResourceProvider
42 //==============================================================================
43 //
44 // This is an abstract base class that encapsulates a drawable graphics
45 // resource.  Subclasses manage specific resource types (Gpu Textures,
46 // GpuMemoryBuffer, Bitmap in RAM). CanvasResourceProvider serves as an
47 // abstraction layer for these resource types. It is designed to serve
48 // the needs of Canvas2DLayerBridge, but can also be used as a general purpose
49 // provider of drawable surfaces for 2D rendering with skia.
50 //
51 // General usage:
52 //   1) Use the Create() static method to create an instance
53 //   2) use Canvas() to get a drawing interface
54 //   3) Call Snapshot() to acquire a bitmap with the rendered image in it.
55 
56 class PLATFORM_EXPORT CanvasResourceProvider
57     : public WebGraphicsContext3DProviderWrapper::DestructionObserver {
58  public:
59   // These values are persisted to logs. Entries should not be renumbered and
60   // numeric values should never be reused.
61   // todo(juanmihd@) ResourceUsage will be removed soon, try avoiding using this
62   enum class ResourceUsage {
63     kSoftwareResourceUsage = 0,  // deprecated
64     kSoftwareCompositedResourceUsage = 1,
65     kAcceleratedResourceUsage = 2,
66     kAcceleratedCompositedResourceUsage = 3,
67     kAcceleratedDirect2DResourceUsage = 4,
68     kAcceleratedDirect3DResourceUsage = 5,
69     kSoftwareCompositedDirect2DResourceUsage = 6,  // deprecated
70     kMaxValue = kSoftwareCompositedDirect2DResourceUsage,
71   };
72 
73   // Bitmask of allowed presentation modes.
74   enum : uint8_t {
75     // GPU Texture or shared memory bitmap
76     kDefaultPresentationMode = 0,
77     // Allow CHROMIUM_image gl extension
78     kAllowImageChromiumPresentationMode = 1 << 0,
79     // Allow swap chains (only on Windows)
80     kAllowSwapChainPresentationMode = 1 << 1,
81   };
82 
83   // These values are persisted to logs. Entries should not be renumbered and
84   // numeric values should never be reused.
85   enum ResourceProviderType {
86     kTexture = 0,
87     kBitmap = 1,
88     kSharedBitmap = 2,
89     kTextureGpuMemoryBuffer = 3,
90     kBitmapGpuMemoryBuffer = 4,
91     kSharedImage = 5,
92     kDirectGpuMemoryBuffer = 6,
93     kPassThrough = 7,
94     kSwapChain = 8,
95     kMaxValue = kSwapChain,
96   };
97 
98   using RestoreMatrixClipStackCb =
99       base::RepeatingCallback<void(cc::PaintCanvas*)>;
100 
101   // todo(juanmihd@) Check whether SkFilterQuality is needed in all of this, or
102   // just call setFilterQuality explicitly
103   static std::unique_ptr<CanvasResourceProvider> CreateBitmapProvider(
104       const IntSize&,
105       SkFilterQuality,
106       const CanvasColorParams&);
107 
108   // Specifies whether the provider should rasterize paint commands on the CPU
109   // or GPU. This is used to support software raster with GPU compositing
110   enum class RasterMode {
111     kGPU,
112     kCPU,
113   };
114 
115   static std::unique_ptr<CanvasResourceProvider> CreateSharedImageProvider(
116       const IntSize&,
117       base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
118       SkFilterQuality,
119       const CanvasColorParams&,
120       bool is_origin_top_left,
121       RasterMode raster_mode,
122       uint32_t shared_image_usage_flags);
123 
124   // TODO(juanmihd): Clean up creation methods/usage. See crbug.com/1035589.
125   static std::unique_ptr<CanvasResourceProvider> Create(
126       const IntSize&,
127       ResourceUsage,
128       base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
129       unsigned msaa_sample_count,
130       SkFilterQuality,
131       const CanvasColorParams&,
132       uint8_t presentation_mode,
133       base::WeakPtr<CanvasResourceDispatcher>,
134       bool is_origin_top_left = true);
135 
136   // Use Snapshot() for capturing a frame that is intended to be displayed via
137   // the compositor. Cases that are destined to be transferred via a
138   // TransferableResource should call ProduceCanvasResource() instead.
139   // The ImageOrientationEnum conveys the desired orientation of the image, and
140   // should be derived from the source of the bitmap data.
141   virtual scoped_refptr<CanvasResource> ProduceCanvasResource() = 0;
142   virtual scoped_refptr<StaticBitmapImage> Snapshot(
143       const ImageOrientation& = kDefaultImageOrientation) = 0;
144 
145   // WebGraphicsContext3DProvider::DestructionObserver implementation.
146   void OnContextDestroyed() override;
147 
148   cc::PaintCanvas* Canvas();
149   void ReleaseLockedImages();
150   sk_sp<cc::PaintRecord> FlushCanvas();
ColorParams()151   const CanvasColorParams& ColorParams() const { return color_params_; }
SetFilterQuality(SkFilterQuality quality)152   void SetFilterQuality(SkFilterQuality quality) { filter_quality_ = quality; }
Size()153   const IntSize& Size() const { return size_; }
IsOriginTopLeft()154   bool IsOriginTopLeft() const { return is_origin_top_left_; }
155   virtual bool IsValid() const = 0;
156   virtual bool IsAccelerated() const = 0;
157   // Returns true if the resource can be used by the display compositor.
158   virtual bool SupportsDirectCompositing() const = 0;
SupportsSingleBuffering()159   virtual bool SupportsSingleBuffering() const { return false; }
160   uint32_t ContentUniqueID() const;
ResourceDispatcher()161   CanvasResourceDispatcher* ResourceDispatcher() {
162     return resource_dispatcher_.get();
163   }
164 
165   // Indicates that the compositing path is single buffered, meaning that
166   // ProduceCanvasResource() return a reference to the same resource each time,
167   // which implies that Producing an animation frame may overwrite the resource
168   // used by the previous frame. This results in graphics updates skipping the
169   // queue, thus reducing latency, but with the possible side effects of tearing
170   // (in cases where the resource is scanned out directly) and irregular frame
171   // rate.
IsSingleBuffered()172   bool IsSingleBuffered() const { return is_single_buffered_; }
173 
174   // Attempt to enable single buffering mode on this resource provider.  May
175   // fail if the CanvasResourcePRovider subclass does not support this mode of
176   // operation.
177   void TryEnableSingleBuffering();
178 
179   // Only works in single buffering mode.
180   bool ImportResource(scoped_refptr<CanvasResource>);
181 
182   void RecycleResource(scoped_refptr<CanvasResource>);
183   void SetResourceRecyclingEnabled(bool);
184   void ClearRecycledResources();
185   scoped_refptr<CanvasResource> NewOrRecycledResource();
186 
187   SkSurface* GetSkSurface() const;
188   bool IsGpuContextLost() const;
189   bool WritePixels(const SkImageInfo& orig_info,
190                    const void* pixels,
191                    size_t row_bytes,
192                    int x,
193                    int y);
194 
GetBackingMailboxForOverwrite(MailboxSyncMode sync_mode)195   virtual gpu::Mailbox GetBackingMailboxForOverwrite(
196       MailboxSyncMode sync_mode) {
197     NOTREACHED();
198     return gpu::Mailbox();
199   }
GetBackingTextureTarget()200   virtual GLenum GetBackingTextureTarget() const { return GL_TEXTURE_2D; }
GetPixelBufferAddressForOverwrite()201   virtual void* GetPixelBufferAddressForOverwrite() {
202     NOTREACHED();
203     return nullptr;
204   }
205   void Clear();
206   ~CanvasResourceProvider() override;
207 
CreateWeakPtr()208   base::WeakPtr<CanvasResourceProvider> CreateWeakPtr() {
209     return weak_ptr_factory_.GetWeakPtr();
210   }
211 
212   // Notifies the provider when the texture params associated with |resource|
213   // are modified externally from the provider's SkSurface.
NotifyTexParamsModified(const CanvasResource * resource)214   virtual void NotifyTexParamsModified(const CanvasResource* resource) {}
215 
cached_resources_count_for_testing()216   size_t cached_resources_count_for_testing() const {
217     return canvas_resources_.size();
218   }
219 
220   void SkipQueuedDrawCommands();
221   void SetRestoreClipStackCallback(RestoreMatrixClipStackCb);
needs_flush()222   bool needs_flush() const { return needs_flush_; }
223   void RestoreBackBuffer(const cc::PaintImage&);
224 
GetType()225   ResourceProviderType GetType() const { return type_; }
226   bool HasRecordedDrawOps() const;
227 
228   void OnDestroyResource();
229 
230  protected:
231   class CanvasImageProvider;
232 
233   gpu::gles2::GLES2Interface* ContextGL() const;
234   gpu::raster::RasterInterface* RasterInterface() const;
235   GrContext* GetGrContext() const;
ContextProviderWrapper()236   base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper() {
237     return context_provider_wrapper_;
238   }
GetMSAASampleCount()239   unsigned GetMSAASampleCount() const { return msaa_sample_count_; }
GetGrSurfaceOrigin()240   GrSurfaceOrigin GetGrSurfaceOrigin() const {
241     return is_origin_top_left_ ? kTopLeft_GrSurfaceOrigin
242                                : kBottomLeft_GrSurfaceOrigin;
243   }
FilterQuality()244   SkFilterQuality FilterQuality() const { return filter_quality_; }
245   scoped_refptr<StaticBitmapImage> SnapshotInternal(const ImageOrientation&);
246   scoped_refptr<CanvasResource> GetImportedResource() const;
247 
248   CanvasResourceProvider(const ResourceProviderType&,
249                          const IntSize&,
250                          unsigned msaa_sample_count,
251                          SkFilterQuality,
252                          const CanvasColorParams&,
253                          bool is_origin_top_left,
254                          base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
255                          base::WeakPtr<CanvasResourceDispatcher>);
256 
257   // Its important to use this method for generating PaintImage wrapped canvas
258   // snapshots to get a cache hit from cc's ImageDecodeCache. This method
259   // ensures that the PaintImage ID for the snapshot, used for keying
260   // decodes/uploads in the cache is invalidated only when the canvas contents
261   // change.
262   cc::PaintImage MakeImageSnapshot();
263   virtual void RasterRecord(sk_sp<cc::PaintRecord>);
264   CanvasImageProvider* GetOrCreateCanvasImageProvider();
265 
266   ResourceProviderType type_;
267   mutable sk_sp<SkSurface> surface_;  // mutable for lazy init
268   SkSurface::ContentChangeMode mode_ = SkSurface::kRetain_ContentChangeMode;
269 
270  private:
271   virtual sk_sp<SkSurface> CreateSkSurface() const = 0;
272   virtual scoped_refptr<CanvasResource> CreateResource();
use_hardware_decode_cache()273   bool use_hardware_decode_cache() const {
274     return IsAccelerated() && context_provider_wrapper_;
275   }
276   // Notifies before any drawing will be done on the resource used by this
277   // provider.
WillDraw()278   virtual void WillDraw() {}
279 
280   cc::ImageDecodeCache* ImageDecodeCacheRGBA8();
281   cc::ImageDecodeCache* ImageDecodeCacheF16();
282   void EnsureSkiaCanvas();
SetNeedsFlush()283   void SetNeedsFlush() { needs_flush_ = true; }
284 
285   base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
286   base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher_;
287   const IntSize size_;
288   const unsigned msaa_sample_count_;
289   SkFilterQuality filter_quality_;
290   const CanvasColorParams color_params_;
291   const bool is_origin_top_left_;
292   std::unique_ptr<CanvasImageProvider> canvas_image_provider_;
293   std::unique_ptr<cc::SkiaPaintCanvas> skia_canvas_;
294   std::unique_ptr<PaintRecorder> recorder_;
295 
296   bool needs_flush_ = false;
297 
298   const cc::PaintImage::Id snapshot_paint_image_id_;
299   cc::PaintImage::ContentId snapshot_paint_image_content_id_ =
300       cc::PaintImage::kInvalidContentId;
301   uint32_t snapshot_sk_image_id_ = 0u;
302 
303   // When and if |resource_recycling_enabled_| is false, |canvas_resources_|
304   // will only hold one CanvasResource at most.
305   WTF::Vector<scoped_refptr<CanvasResource>> canvas_resources_;
306   bool resource_recycling_enabled_ = true;
307   bool is_single_buffered_ = false;
308 
309   // The maximum number of in-flight resources waiting to be used for recycling.
310   static constexpr int kMaxRecycledCanvasResources = 2;
311   // The maximum number of draw ops executed on the canvas, after which the
312   // underlying GrContext is flushed.
313   static constexpr int kMaxDrawsBeforeContextFlush = 50;
314 
315   size_t num_inflight_resources_ = 0;
316   size_t max_inflight_resources_ = 0;
317 
318   RestoreMatrixClipStackCb restore_clip_stack_callback_;
319 
320   base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_{this};
321 
322   DISALLOW_COPY_AND_ASSIGN(CanvasResourceProvider);
323 };
324 
325 }  // namespace blink
326 
327 #endif
328