summaryrefslogtreecommitdiffstats
path: root/dom/canvas/DrawTargetWebgl.h
blob: 8dc9fff04889b2a2b99503f30710111977e792c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
/* -*- 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_DRAWTARGETWEBGL_H
#define _MOZILLA_GFX_DRAWTARGETWEBGL_H

#include "GLTypes.h"
#include "mozilla/Array.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathSkia.h"
#include "mozilla/LinkedList.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/layers/LayersTypes.h"

#include <vector>

namespace WGR {
struct OutputVertex;
struct PathBuilder;
}  // namespace WGR

namespace mozilla {

class WebGLContext;
class WebGLBuffer;
class WebGLFramebuffer;
class WebGLProgram;
class WebGLRenderbuffer;
class WebGLTexture;
class WebGLUniformLocation;
class WebGLVertexArray;

namespace gl {
class GLContext;
}  // namespace gl

namespace layers {
class RemoteTextureOwnerClient;
}  // namespace layers

namespace gfx {

class DataSourceSurface;
class DrawTargetSkia;
class DrawTargetWebgl;
class PathSkia;
class SourceSurfaceSkia;
class SourceSurfaceWebgl;

class TextureHandle;
class SharedTexture;
class SharedTextureHandle;
class StandaloneTexture;
class GlyphCache;
class PathCache;
struct PathVertexRange;

// SharedContextWebgl stores most of the actual WebGL state that may be used by
// any number of DrawTargetWebgl's that use it. Foremost, it holds the actual
// WebGL client context, programs, and buffers for mapping to WebGL.
// Secondarily, it holds shared caches for surfaces, glyphs, paths, and
// shadows so that each DrawTargetWebgl does not require its own cache. It is
// important that SetTarget is called to install the current DrawTargetWebgl
// before actually using the SharedContext, as the individual framebuffers
// and viewport are still maintained in DrawTargetWebgl itself.
class SharedContextWebgl : public mozilla::RefCounted<SharedContextWebgl>,
                           public mozilla::SupportsWeakPtr {
  friend class DrawTargetWebgl;
  friend class SourceSurfaceWebgl;
  friend class TextureHandle;
  friend class SharedTextureHandle;
  friend class StandaloneTexture;

 public:
  MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedContextWebgl)

  static already_AddRefed<SharedContextWebgl> Create();

  ~SharedContextWebgl();

  gl::GLContext* GetGLContext();

  void EnterTlsScope();
  void ExitTlsScope();

  bool IsContextLost() const;

  void OnMemoryPressure();

  void ClearCaches();

 private:
  SharedContextWebgl();

  WeakPtr<DrawTargetWebgl> mCurrentTarget;
  IntSize mViewportSize;
  // The current integer-aligned scissor rect.
  IntRect mClipRect;
  // The current fractional AA'd clip rect bounds.
  Rect mClipAARect;

  RefPtr<WebGLContext> mWebgl;

  // Avoid spurious state changes by caching last used state.
  RefPtr<WebGLProgram> mLastProgram;
  RefPtr<WebGLTexture> mLastTexture;
  RefPtr<WebGLTexture> mLastClipMask;

  // WebGL shader resources
  RefPtr<WebGLBuffer> mPathVertexBuffer;
  RefPtr<WebGLVertexArray> mPathVertexArray;
  // The current insertion offset into the GPU path buffer.
  uint32_t mPathVertexOffset = 0;
  // The maximum size of the GPU path buffer.
  uint32_t mPathVertexCapacity = 0;
  // The maximum supported type complexity of a GPU path.
  uint32_t mPathMaxComplexity = 0;
  // Whether to accelerate stroked paths with AAStroke.
  bool mPathAAStroke = true;
  // Whether to accelerate stroked paths with WGR.
  bool mPathWGRStroke = false;

  WGR::PathBuilder* mWGRPathBuilder = nullptr;
  // Temporary buffer for generating WGR output into.
  UniquePtr<WGR::OutputVertex[]> mWGROutputBuffer;

  RefPtr<WebGLProgram> mSolidProgram;
  Maybe<uint32_t> mSolidProgramViewport;
  Maybe<uint32_t> mSolidProgramAA;
  Maybe<uint32_t> mSolidProgramTransform;
  Maybe<uint32_t> mSolidProgramColor;
  Maybe<uint32_t> mSolidProgramClipMask;
  Maybe<uint32_t> mSolidProgramClipBounds;
  RefPtr<WebGLProgram> mImageProgram;
  Maybe<uint32_t> mImageProgramViewport;
  Maybe<uint32_t> mImageProgramAA;
  Maybe<uint32_t> mImageProgramTransform;
  Maybe<uint32_t> mImageProgramTexMatrix;
  Maybe<uint32_t> mImageProgramTexBounds;
  Maybe<uint32_t> mImageProgramColor;
  Maybe<uint32_t> mImageProgramSwizzle;
  Maybe<uint32_t> mImageProgramSampler;
  Maybe<uint32_t> mImageProgramClipMask;
  Maybe<uint32_t> mImageProgramClipBounds;

  struct SolidProgramUniformState {
    Maybe<Array<float, 2>> mViewport;
    Maybe<Array<float, 1>> mAA;
    Maybe<Array<float, 6>> mTransform;
    Maybe<Array<float, 4>> mColor;
    Maybe<Array<float, 4>> mClipBounds;
  } mSolidProgramUniformState;

  struct ImageProgramUniformState {
    Maybe<Array<float, 2>> mViewport;
    Maybe<Array<float, 1>> mAA;
    Maybe<Array<float, 6>> mTransform;
    Maybe<Array<float, 6>> mTexMatrix;
    Maybe<Array<float, 4>> mTexBounds;
    Maybe<Array<float, 4>> mColor;
    Maybe<Array<float, 1>> mSwizzle;
    Maybe<Array<float, 4>> mClipBounds;
  } mImageProgramUniformState;

  // Scratch framebuffer used to wrap textures for miscellaneous utility ops.
  RefPtr<WebGLFramebuffer> mScratchFramebuffer;
  // Buffer filled with zero data for initializing textures.
  RefPtr<WebGLBuffer> mZeroBuffer;
  size_t mZeroSize = 0;
  // 1x1 texture with solid white mask for disabling clipping
  RefPtr<WebGLTexture> mNoClipMask;

  uint32_t mMaxTextureSize = 0;
  bool mRasterizationTruncates = false;

  // The current blending operation.
  CompositionOp mLastCompositionOp = CompositionOp::OP_SOURCE;
  // The constant blend color used for the blending operation.
  Maybe<DeviceColor> mLastBlendColor;

  // The cached scissor state. Operations that rely on scissor state should
  // take care to enable or disable the cached scissor state as necessary.
  bool mScissorEnabled = false;
  IntRect mLastScissor = {-1, -1, -1, -1};

  // A most-recently-used list of allocated texture handles.
  LinkedList<RefPtr<TextureHandle>> mTextureHandles;
  size_t mNumTextureHandles = 0;
  // User data key linking a SourceSurface with its TextureHandle.
  UserDataKey mTextureHandleKey = {0};
  // User data key linking a SourceSurface with its shadow blur TextureHandle.
  UserDataKey mShadowTextureKey = {0};
  // User data key linking a ScaledFont with its GlyphCache.
  UserDataKey mGlyphCacheKey = {0};
  // List of all GlyphCaches currently allocated to fonts.
  LinkedList<GlyphCache> mGlyphCaches;
  // Cache of rasterized paths.
  UniquePtr<PathCache> mPathCache;
  // Collection of allocated shared texture pages that may be shared amongst
  // many handles.
  std::vector<RefPtr<SharedTexture>> mSharedTextures;
  // Collection of allocated standalone textures that have a single assigned
  // handle.
  std::vector<RefPtr<StandaloneTexture>> mStandaloneTextures;
  size_t mUsedTextureMemory = 0;
  size_t mTotalTextureMemory = 0;
  // The total reserved memory for empty texture pages that are kept around
  // for future allocations.
  size_t mEmptyTextureMemory = 0;
  // A memory pressure event may signal from another thread that caches should
  // be cleared if possible.
  Atomic<bool> mShouldClearCaches;
  // The total number of DrawTargetWebgls using this shared context.
  size_t mDrawTargetCount = 0;
  // Whether we are inside a scoped usage of TLS MakeCurrent, and what previous
  // value to restore it to when exiting the scope.
  Maybe<bool> mTlsScope;

  // Cached unit circle path
  RefPtr<Path> mUnitCirclePath;

  bool Initialize();
  bool CreateShaders();
  void ResetPathVertexBuffer(bool aChanged = true);

  void BlendFunc(GLenum aSrcFactor, GLenum aDstFactor);
  void SetBlendState(CompositionOp aOp,
                     const Maybe<DeviceColor>& aColor = Nothing());

  void SetClipRect(const Rect& aClipRect);
  void SetClipRect(const IntRect& aClipRect) { SetClipRect(Rect(aClipRect)); }
  bool SetClipMask(const RefPtr<WebGLTexture>& aTex);
  bool SetNoClipMask();
  bool HasClipMask() const {
    return mLastClipMask && mLastClipMask != mNoClipMask;
  }

  Maybe<uint32_t> GetUniformLocation(const RefPtr<WebGLProgram>& prog,
                                     const std::string& aName) const;

  template <class T, size_t N>
  void UniformData(GLenum aFuncElemType, const Maybe<uint32_t>& aLoc,
                   const Array<T, N>& aData);

  // Avoids redundant UniformData calls by caching the previously set value.
  template <class T, size_t N>
  void MaybeUniformData(GLenum aFuncElemType, const Maybe<uint32_t>& aLoc,
                        const Array<T, N>& aData, Maybe<Array<T, N>>& aCached);

  bool IsCurrentTarget(DrawTargetWebgl* aDT) const {
    return aDT == mCurrentTarget;
  }
  bool SetTarget(DrawTargetWebgl* aDT);

  // Reset the current target.
  void ClearTarget() { mCurrentTarget = nullptr; }
  // Reset the last used texture to force binding next use.
  void ClearLastTexture(bool aFullClear = false);

  bool SupportsPattern(const Pattern& aPattern);

  void EnableScissor(const IntRect& aRect);
  void DisableScissor();

  void SetTexFilter(WebGLTexture* aTex, bool aFilter);
  void InitTexParameters(WebGLTexture* aTex, bool aFilter = true);

  bool ReadInto(uint8_t* aDstData, int32_t aDstStride, SurfaceFormat aFormat,
                const IntRect& aBounds, TextureHandle* aHandle = nullptr);
  already_AddRefed<DataSourceSurface> ReadSnapshot(
      TextureHandle* aHandle = nullptr);
  already_AddRefed<TextureHandle> WrapSnapshot(const IntSize& aSize,
                                               SurfaceFormat aFormat,
                                               RefPtr<WebGLTexture> aTex);
  already_AddRefed<TextureHandle> CopySnapshot(
      const IntRect& aRect, TextureHandle* aHandle = nullptr);

  already_AddRefed<WebGLTexture> GetCompatibleSnapshot(
      SourceSurface* aSurface) const;
  bool IsCompatibleSurface(SourceSurface* aSurface) const;

  bool UploadSurface(DataSourceSurface* aData, SurfaceFormat aFormat,
                     const IntRect& aSrcRect, const IntPoint& aDstOffset,
                     bool aInit, bool aZero = false,
                     const RefPtr<WebGLTexture>& aTex = nullptr);
  already_AddRefed<TextureHandle> AllocateTextureHandle(
      SurfaceFormat aFormat, const IntSize& aSize, bool aAllowShared = true,
      bool aRenderable = false);
  void DrawQuad();
  void DrawTriangles(const PathVertexRange& aRange);
  bool DrawRectAccel(const Rect& aRect, const Pattern& aPattern,
                     const DrawOptions& aOptions,
                     Maybe<DeviceColor> aMaskColor = Nothing(),
                     RefPtr<TextureHandle>* aHandle = nullptr,
                     bool aTransformed = true, bool aClipped = true,
                     bool aAccelOnly = false, bool aForceUpdate = false,
                     const StrokeOptions* aStrokeOptions = nullptr,
                     const PathVertexRange* aVertexRange = nullptr,
                     const Matrix* aRectXform = nullptr);

  already_AddRefed<TextureHandle> DrawStrokeMask(
      const PathVertexRange& aVertexRange, const IntSize& aSize);
  bool DrawPathAccel(const Path* aPath, const Pattern& aPattern,
                     const DrawOptions& aOptions,
                     const StrokeOptions* aStrokeOptions = nullptr,
                     bool aAllowStrokeAlpha = false,
                     const ShadowOptions* aShadow = nullptr,
                     bool aCacheable = true,
                     const Matrix* aPathXform = nullptr);

  bool DrawCircleAccel(const Point& aCenter, float aRadius,
                       const Pattern& aPattern, const DrawOptions& aOptions,
                       const StrokeOptions* aStrokeOptions = nullptr);

  bool DrawGlyphsAccel(ScaledFont* aFont, const GlyphBuffer& aBuffer,
                       const Pattern& aPattern, const DrawOptions& aOptions,
                       const StrokeOptions* aStrokeOptions,
                       bool aUseSubpixelAA);

  void PruneTextureHandle(const RefPtr<TextureHandle>& aHandle);
  bool PruneTextureMemory(size_t aMargin = 0, bool aPruneUnused = true);

  bool RemoveSharedTexture(const RefPtr<SharedTexture>& aTexture);
  bool RemoveStandaloneTexture(const RefPtr<StandaloneTexture>& aTexture);

  void UnlinkSurfaceTextures();
  void UnlinkSurfaceTexture(const RefPtr<TextureHandle>& aHandle);
  void UnlinkGlyphCaches();

  void ClearAllTextures();
  void ClearEmptyTextureMemory();
  void ClearCachesIfNecessary();

  void CachePrefs();
};

// DrawTargetWebgl implements a subset of the DrawTarget API suitable for use
// by CanvasRenderingContext2D. It maps these to a client WebGL context so that
// they can be accelerated where possible by WebGL. It manages both routing to
// appropriate shaders and texture allocation/caching for surfaces. For commands
// that are not feasible to accelerate with WebGL, it mirrors state to a backup
// DrawTargetSkia that can be used as a fallback software renderer. Multiple
// instances of DrawTargetWebgl within a process will actually share a single
// WebGL context so that data can be more easily interchanged between them and
// also to enable more reasonable limiting of resource usage.
class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
  friend class SourceSurfaceWebgl;
  friend class SharedContextWebgl;

 public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetWebgl, override)

 private:
  IntSize mSize;
  RefPtr<WebGLFramebuffer> mFramebuffer;
  RefPtr<WebGLTexture> mTex;
  RefPtr<WebGLTexture> mClipMask;
  // The integer-aligned, scissor-compatible conservative bounds of the clip.
  IntRect mClipBounds;
  // The fractional, AA'd bounds of the clip rect, if applicable.
  Rect mClipAARect;
  RefPtr<DrawTargetSkia> mSkia;
  // Skia DT pointing to the same pixel data, but without any applied clips.
  RefPtr<DrawTargetSkia> mSkiaNoClip;
  // The Shmem backing the Skia DT, if applicable.
  RefPtr<mozilla::ipc::SharedMemoryBasic> mShmem;
  // The currently cached snapshot of the WebGL context
  RefPtr<SourceSurfaceWebgl> mSnapshot;
  // The mappable size of mShmem.
  uint32_t mShmemSize = 0;
  // Whether the framebuffer is still in the initially clear state.
  bool mIsClear = true;
  // Whether or not the Skia target has valid contents and is being drawn to
  bool mSkiaValid = false;
  // Whether or not Skia layering over the WebGL context is enabled
  bool mSkiaLayer = false;
  // Whether the WebGL target was clear when the Skia layer was established.
  bool mSkiaLayerClear = false;
  // Whether or not the WebGL context has valid contents and is being drawn to
  bool mWebglValid = true;
  // Whether or not the clip state has changed since last used by
  // SharedContextWebgl.
  bool mClipChanged = true;
  // Whether or not the clip state needs to be refreshed. Sometimes the clip
  // state may be overwritten and require a refresh later, even though it has
  // not changed.
  bool mRefreshClipState = true;
  // The number of layers currently pushed.
  int32_t mLayerDepth = 0;

  RefPtr<TextureHandle> mSnapshotTexture;

  // Store a log of clips currently pushed so that they can be used to init
  // the clip state of temporary DTs.
  struct ClipStack {
    Matrix mTransform;
    Rect mRect;
    RefPtr<const Path> mPath;

    bool operator==(const ClipStack& aOther) const;
  };

  std::vector<ClipStack> mClipStack;

  // The previous state of the clip stack when a mask was generated.
  std::vector<ClipStack> mCachedClipStack;

  // UsageProfile stores per-frame counters for significant profiling events
  // that assist in determining whether acceleration should still be used for
  // a Canvas2D user.
  struct UsageProfile {
    uint32_t mFailedFrames = 0;
    uint32_t mFrameCount = 0;
    uint32_t mCacheMisses = 0;
    uint32_t mCacheHits = 0;
    uint32_t mUncachedDraws = 0;
    uint32_t mLayers = 0;
    uint32_t mReadbacks = 0;
    uint32_t mFallbacks = 0;

    void BeginFrame();
    void EndFrame();
    bool RequiresRefresh() const;

    void OnCacheMiss() { ++mCacheMisses; }
    void OnCacheHit() { ++mCacheHits; }
    void OnUncachedDraw() { ++mUncachedDraws; }
    void OnLayer() { ++mLayers; }
    void OnReadback() { ++mReadbacks; }
    void OnFallback() { ++mFallbacks; }
  };

  UsageProfile mProfile;

  RefPtr<SharedContextWebgl> mSharedContext;

 public:
  DrawTargetWebgl();
  ~DrawTargetWebgl();

  static bool CanCreate(const IntSize& aSize, SurfaceFormat aFormat);
  static already_AddRefed<DrawTargetWebgl> Create(
      const IntSize& aSize, SurfaceFormat aFormat,
      const RefPtr<SharedContextWebgl>& aSharedContext);

  bool Init(const IntSize& aSize, SurfaceFormat aFormat,
            const RefPtr<SharedContextWebgl>& aSharedContext);

  bool IsValid() const override;

  DrawTargetType GetType() const override {
    return DrawTargetType::HARDWARE_RASTER;
  }
  BackendType GetBackendType() const override { return BackendType::WEBGL; }
  IntSize GetSize() const override { return mSize; }
  const RefPtr<SharedContextWebgl>& GetSharedContext() const {
    return mSharedContext;
  }

  bool HasDataSnapshot() const;
  bool EnsureDataSnapshot();
  void PrepareShmem();
  already_AddRefed<SourceSurface> GetDataSnapshot();
  already_AddRefed<SourceSurface> Snapshot() override;
  already_AddRefed<SourceSurface> GetOptimizedSnapshot(DrawTarget* aTarget);
  already_AddRefed<SourceSurface> GetBackingSurface() override;
  void DetachAllSnapshots() override;

  void BeginFrame(bool aInvalidContents = false);
  void EndFrame();
  bool RequiresRefresh() const { return mProfile.RequiresRefresh(); }

  bool LockBits(uint8_t** aData, IntSize* aSize, int32_t* aStride,
                SurfaceFormat* aFormat, IntPoint* aOrigin = nullptr) override;
  void ReleaseBits(uint8_t* aData) override;

  void Flush() override {}
  void DrawSurface(
      SourceSurface* aSurface, const Rect& aDest, const Rect& aSource,
      const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
      const DrawOptions& aOptions = DrawOptions()) override;
  void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
                  const Point& aDestPoint,
                  const DrawOptions& aOptions = DrawOptions()) override;
  void DrawSurfaceWithShadow(SourceSurface* aSurface, const Point& aDest,
                             const ShadowOptions& aShadow,
                             CompositionOp aOperator) override;
  void DrawShadow(const Path* aPath, const Pattern& aPattern,
                  const ShadowOptions& aShadow, const DrawOptions& aOptions,
                  const StrokeOptions* aStrokeOptions = nullptr) override;

  void ClearRect(const Rect& aRect) override;
  void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
                   const IntPoint& aDestination) override;
  void FillRect(const Rect& aRect, const Pattern& aPattern,
                const DrawOptions& aOptions = DrawOptions()) override;
  void StrokeRect(const Rect& aRect, const Pattern& aPattern,
                  const StrokeOptions& aStrokeOptions = StrokeOptions(),
                  const DrawOptions& aOptions = DrawOptions()) override;
  bool StrokeLineAccel(const Point& aStart, const Point& aEnd,
                       const Pattern& aPattern,
                       const StrokeOptions& aStrokeOptions,
                       const DrawOptions& aOptions, bool aClosed = false);
  void StrokeLine(const Point& aStart, const Point& aEnd,
                  const Pattern& aPattern,
                  const StrokeOptions& aStrokeOptions = StrokeOptions(),
                  const DrawOptions& aOptions = DrawOptions()) override;
  void Stroke(const Path* aPath, const Pattern& aPattern,
              const StrokeOptions& aStrokeOptions = StrokeOptions(),
              const DrawOptions& aOptions = DrawOptions()) override;
  void Fill(const Path* aPath, const Pattern& aPattern,
            const DrawOptions& aOptions = DrawOptions()) override;
  void FillCircle(const Point& aOrigin, float aRadius, const Pattern& aPattern,
                  const DrawOptions& aOptions = DrawOptions()) override;
  void StrokeCircle(const Point& aOrigin, float aRadius,
                    const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions = StrokeOptions(),
                    const DrawOptions& aOptions = DrawOptions()) override;

  void SetPermitSubpixelAA(bool aPermitSubpixelAA) override;
  void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
                  const Pattern& aPattern,
                  const DrawOptions& aOptions = DrawOptions()) override;
  void StrokeGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
                    const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions = StrokeOptions(),
                    const DrawOptions& aOptions = DrawOptions()) override;
  void Mask(const Pattern& aSource, const Pattern& aMask,
            const DrawOptions& aOptions = DrawOptions()) override;
  void MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset,
                   const DrawOptions& aOptions = DrawOptions()) override;
  bool Draw3DTransformedSurface(SourceSurface* aSurface,
                                const Matrix4x4& aMatrix) override;
  void PushClip(const Path* aPath) override;
  void PushClipRect(const Rect& aRect) override;
  void PushDeviceSpaceClipRects(const IntRect* aRects,
                                uint32_t aCount) override;
  void PopClip() override;
  bool RemoveAllClips() override;
  void CopyToFallback(DrawTarget* aDT);
  void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
                 const Matrix& aMaskTransform,
                 const IntRect& aBounds = IntRect(),
                 bool aCopyBackground = false) override;
  void PushLayerWithBlend(
      bool aOpaque, Float aOpacity, SourceSurface* aMask,
      const Matrix& aMaskTransform, const IntRect& aBounds = IntRect(),
      bool aCopyBackground = false,
      CompositionOp aCompositionOp = CompositionOp::OP_OVER) override;
  void PopLayer() override;
  already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(
      unsigned char* aData, const IntSize& aSize, int32_t aStride,
      SurfaceFormat aFormat) const override;
  already_AddRefed<SourceSurface> OptimizeSourceSurface(
      SourceSurface* aSurface) const override;
  already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(
      SourceSurface* aSurface) const override;
  already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
      const NativeSurface& aSurface) const override;
  already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
      const IntSize& aSize, SurfaceFormat aFormat) const override;
  bool CanCreateSimilarDrawTarget(const IntSize& aSize,
                                  SurfaceFormat aFormat) const override;
  RefPtr<DrawTarget> CreateClippedDrawTarget(const Rect& aBounds,
                                             SurfaceFormat aFormat) override;

  already_AddRefed<PathBuilder> CreatePathBuilder(
      FillRule aFillRule = FillRule::FILL_WINDING) const override;
  already_AddRefed<GradientStops> CreateGradientStops(
      GradientStop* aStops, uint32_t aNumStops,
      ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
  already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
  void SetTransform(const Matrix& aTransform) override;
  void* GetNativeSurface(NativeSurfaceType aType) override;

  bool CopyToSwapChain(
      layers::TextureType aTextureType, layers::RemoteTextureId aId,
      layers::RemoteTextureOwnerId aOwnerId,
      layers::RemoteTextureOwnerClient* aOwnerClient = nullptr);

  void OnMemoryPressure() { mSharedContext->OnMemoryPressure(); }

  operator std::string() const {
    std::stringstream stream;
    stream << "DrawTargetWebgl(" << this << ")";
    return stream.str();
  }

  mozilla::ipc::SharedMemoryBasic::Handle TakeShmemHandle() const {
    return mShmem ? mShmem->TakeHandle()
                  : mozilla::ipc::SharedMemoryBasic::NULLHandle();
  }

  uint32_t GetShmemSize() const { return mShmemSize; }

 private:
  bool SupportsPattern(const Pattern& aPattern) {
    return mSharedContext->SupportsPattern(aPattern);
  }

  bool SetSimpleClipRect();
  bool GenerateComplexClipMask();
  bool PrepareContext(bool aClipped = true);

  void DrawRectFallback(const Rect& aRect, const Pattern& aPattern,
                        const DrawOptions& aOptions,
                        Maybe<DeviceColor> aMaskColor = Nothing(),
                        bool aTransform = true, bool aClipped = true,
                        const StrokeOptions* aStrokeOptions = nullptr);
  bool DrawRect(const Rect& aRect, const Pattern& aPattern,
                const DrawOptions& aOptions,
                Maybe<DeviceColor> aMaskColor = Nothing(),
                RefPtr<TextureHandle>* aHandle = nullptr,
                bool aTransformed = true, bool aClipped = true,
                bool aAccelOnly = false, bool aForceUpdate = false,
                const StrokeOptions* aStrokeOptions = nullptr);

  ColorPattern GetClearPattern() const;

  bool RectContainsViewport(const Rect& aRect) const;

  bool ShouldAccelPath(const DrawOptions& aOptions,
                       const StrokeOptions* aStrokeOptions);
  void DrawPath(const Path* aPath, const Pattern& aPattern,
                const DrawOptions& aOptions,
                const StrokeOptions* aStrokeOptions = nullptr,
                bool aAllowStrokeAlpha = false);
  void DrawCircle(const Point& aOrigin, float aRadius, const Pattern& aPattern,
                  const DrawOptions& aOptions,
                  const StrokeOptions* aStrokeOptions = nullptr);

  bool MarkChanged();

  bool ReadIntoSkia();
  void FlattenSkia();
  bool PrepareSkia();
  bool FlushFromSkia();

  void MarkSkiaChanged(bool aOverwrite = false);
  void MarkSkiaChanged(const DrawOptions& aOptions);

  bool ShouldUseSubpixelAA(ScaledFont* aFont, const DrawOptions& aOptions);

  bool ReadInto(uint8_t* aDstData, int32_t aDstStride);
  already_AddRefed<DataSourceSurface> ReadSnapshot();
  already_AddRefed<TextureHandle> CopySnapshot(const IntRect& aRect);
  already_AddRefed<TextureHandle> CopySnapshot() {
    return CopySnapshot(GetRect());
  }

  void ClearSnapshot(bool aCopyOnWrite = true, bool aNeedHandle = false);

  bool CreateFramebuffer();

  // PrepareContext may sometimes be used recursively. When this occurs, ensure
  // that clip state is restored after the context is used.
  struct AutoRestoreContext {
    DrawTargetWebgl* mTarget;
    Rect mClipAARect;
    RefPtr<WebGLTexture> mLastClipMask;

    explicit AutoRestoreContext(DrawTargetWebgl* aTarget);

    ~AutoRestoreContext();
  };
};

}  // namespace gfx
}  // namespace mozilla

#endif  // _MOZILLA_GFX_DRAWTARGETWEBGL_H