summaryrefslogtreecommitdiffstats
path: root/dom/canvas/HostWebGLContext.h
blob: 7c31ad30d9b6846efd7b800a96c9c801c486465e (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
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 HOSTWEBGLCONTEXT_H_
#define HOSTWEBGLCONTEXT_H_

#include "mozilla/dom/BindingUtils.h"
#include "mozilla/GfxMessageUtils.h"
#include "ClientWebGLContext.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "GLContext.h"
#include "WebGLContext.h"
#include "WebGL2Context.h"
#include "WebGLFramebuffer.h"
#include "WebGLTypes.h"
#include "WebGLCommandQueue.h"

#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace mozilla {

namespace dom {
class WebGLParent;
}
namespace layers {
class CompositableHost;
}

struct LockedOutstandingContexts final {
 private:
  // StaticMutexAutoLock lock; // We can't use it directly (STACK_CLASS), but
  // this is effectively what we hold via RAII.

 public:
  const std::unordered_set<HostWebGLContext*>& contexts;

  LockedOutstandingContexts();
  ~LockedOutstandingContexts();
};

/**
 * Host endpoint of a WebGLContext.  HostWebGLContext owns a WebGLContext
 * that it uses to execute commands sent from its ClientWebGLContext.
 *
 * A HostWebGLContext continuously issues a Task to the Compositor thread that
 * causes it to drain its queue of commands.  It also maintains a map of WebGL
 * objects (e.g. ObjectIdMap<WebGLShader>) that it uses associate them with
 * their cross-process IDs.
 *
 * This class is not an implementation of the
 * nsICanvasRenderingContextInternal DOM class.  That is the
 * ClientWebGLContext.
 */
class HostWebGLContext final : public SupportsWeakPtr {
  friend class WebGLContext;
  friend class WebGLMemoryTracker;
  friend class dom::WebGLParent;

  using ObjectId = webgl::ObjectId;

  static std::unique_ptr<LockedOutstandingContexts> OutstandingContexts() {
    return std::make_unique<LockedOutstandingContexts>();
  }

 public:
  struct OwnerData final {
    ClientWebGLContext* inProcess = nullptr;
    dom::WebGLParent* outOfProcess = nullptr;
  };

  static UniquePtr<HostWebGLContext> Create(const OwnerData&,
                                            const webgl::InitContextDesc&,
                                            webgl::InitContextResult* out);

 private:
  explicit HostWebGLContext(const OwnerData&);

 public:
  virtual ~HostWebGLContext();

  WebGLContext* GetWebGLContext() const { return mContext; }

 public:
  const OwnerData mOwnerData;

 private:
  RefPtr<WebGLContext> mContext;

#define _(X) std::unordered_map<ObjectId, RefPtr<WebGL##X>> m##X##Map;

  _(Buffer)
  _(Framebuffer)
  _(Program)
  _(Query)
  _(Renderbuffer)
  _(Sampler)
  _(Shader)
  _(Sync)
  _(Texture)
  _(TransformFeedback)
  _(VertexArray)

#undef _

  class AutoResolveT final {
    friend class HostWebGLContext;

    const HostWebGLContext& mParent;
    const ObjectId mId;

   public:
    AutoResolveT(const HostWebGLContext& parent, const ObjectId id)
        : mParent(parent), mId(id) {}

#define _(X)                                              \
  WebGL##X* As(WebGL##X*) const {                         \
    const auto maybe = MaybeFind(mParent.m##X##Map, mId); \
    if (!maybe) return nullptr;                           \
    return maybe->get();                                  \
  }

    _(Buffer)
    _(Framebuffer)
    _(Program)
    _(Query)
    _(Renderbuffer)
    _(Sampler)
    _(Shader)
    _(Sync)
    _(Texture)
    _(TransformFeedback)
    _(VertexArray)

#undef _
    template <typename T>
    MOZ_IMPLICIT operator T*() const {
      T* coercer = nullptr;
      return As(coercer);
    }

    template <typename T>
    MOZ_IMPLICIT operator const T*() const {
      T* coercer = nullptr;
      return As(coercer);
    }
  };

  AutoResolveT AutoResolve(const ObjectId id) const { return {*this, id}; }
  template <typename T>
  T* ById(const ObjectId id) const {
    T* coercer = nullptr;
    return AutoResolve(id).As(coercer);
  }

  // -------------------------------------------------------------------------
  // Host-side methods.  Calls in the client are forwarded to the host.
  // -------------------------------------------------------------------------

 public:
  // ------------------------- Composition -------------------------

  void SetCompositableHost(RefPtr<layers::CompositableHost>& compositableHost) {
    mContext->SetCompositableHost(compositableHost);
  }

  void Present(const ObjectId xrFb, const layers::TextureType t,
               const bool webvr, const webgl::SwapChainOptions& options) const {
    return (void)mContext->Present(AutoResolve(xrFb), t, webvr, options);
  }
  void CopyToSwapChain(const ObjectId fb, const layers::TextureType t,
                       const webgl::SwapChainOptions& options) const {
    return (void)mContext->CopyToSwapChain(AutoResolve(fb), t, options);
  }
  void EndOfFrame() const { return (void)mContext->EndOfFrame(); }
  Maybe<layers::SurfaceDescriptor> GetFrontBuffer(ObjectId xrFb,
                                                  const bool webvr) const;

  // -

  Maybe<uvec2> FrontBufferSnapshotInto(Maybe<Range<uint8_t>> dest) const {
    return mContext->FrontBufferSnapshotInto(dest);
  }

  Maybe<uvec2> FrontBufferSnapshotInto(
      std::shared_ptr<gl::SharedSurface>& front,
      Maybe<Range<uint8_t>> dest) const {
    return mContext->FrontBufferSnapshotInto(front, dest);
  }

  void ClearVRSwapChain() const { mContext->ClearVRSwapChain(); }

  // -

  void Resize(const uvec2& size) { return mContext->Resize(size); }

  uvec2 DrawingBufferSize() { return mContext->DrawingBufferSize(); }

  void OnMemoryPressure() { return mContext->OnMemoryPressure(); }

  void DidRefresh() { mContext->DidRefresh(); }

  void GenerateError(const GLenum error, const std::string& text) const {
    mContext->GenerateErrorImpl(error, text);
  }

  void OnContextLoss(webgl::ContextLossReason);

  void RequestExtension(const WebGLExtensionID ext) {
    mContext->RequestExtension(ext);
  }

  // -
  // Child-ward

  void JsWarning(const std::string&) const;

  // -
  // Creation and destruction

  void CreateBuffer(ObjectId);
  void CreateFramebuffer(ObjectId);
  bool CreateOpaqueFramebuffer(ObjectId,
                               const webgl::OpaqueFramebufferOptions& options);
  void CreateProgram(ObjectId);
  void CreateQuery(ObjectId);
  void CreateRenderbuffer(ObjectId);
  void CreateSampler(ObjectId);
  void CreateShader(ObjectId, GLenum type);
  void CreateSync(ObjectId);
  void CreateTexture(ObjectId);
  void CreateTransformFeedback(ObjectId);
  void CreateVertexArray(ObjectId);

  void DeleteBuffer(ObjectId);
  void DeleteFramebuffer(ObjectId);
  void DeleteProgram(ObjectId);
  void DeleteQuery(ObjectId);
  void DeleteRenderbuffer(ObjectId);
  void DeleteSampler(ObjectId);
  void DeleteShader(ObjectId);
  void DeleteSync(ObjectId);
  void DeleteTexture(ObjectId);
  void DeleteTransformFeedback(ObjectId);
  void DeleteVertexArray(ObjectId);

  // ------------------------- GL State -------------------------
  bool IsContextLost() const { return mContext->IsContextLost(); }

  void SetEnabled(GLenum cap, Maybe<GLuint> i, bool val) const {
    mContext->SetEnabled(cap, i, val);
  }

  bool IsEnabled(GLenum cap) const { return mContext->IsEnabled(cap); }

  Maybe<double> GetNumber(GLenum pname) const {
    return mContext->GetParameter(pname);
  }

  Maybe<std::string> GetString(GLenum pname) const {
    return mContext->GetString(pname);
  }

  void AttachShader(ObjectId prog, ObjectId shader) const {
    const auto pProg = ById<WebGLProgram>(prog);
    const auto pShader = ById<WebGLShader>(shader);
    if (!pProg || !pShader) return;
    mContext->AttachShader(*pProg, *pShader);
  }

  void BindAttribLocation(ObjectId id, GLuint location,
                          const std::string& name) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return;
    mContext->BindAttribLocation(*obj, location, name);
  }

  void BindFramebuffer(GLenum target, ObjectId id) const {
    mContext->BindFramebuffer(target, AutoResolve(id));
  }

  void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) const {
    mContext->BlendColor(r, g, b, a);
  }

  void BlendEquationSeparate(Maybe<GLuint> i, GLenum modeRGB,
                             GLenum modeAlpha) const {
    mContext->BlendEquationSeparate(i, modeRGB, modeAlpha);
  }

  void BlendFuncSeparate(Maybe<GLuint> i, GLenum srcRGB, GLenum dstRGB,
                         GLenum srcAlpha, GLenum dstAlpha) const {
    mContext->BlendFuncSeparate(i, srcRGB, dstRGB, srcAlpha, dstAlpha);
  }

  GLenum CheckFramebufferStatus(GLenum target) const {
    return mContext->CheckFramebufferStatus(target);
  }

  void Clear(GLbitfield mask) const { mContext->Clear(mask); }

  void ClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) const {
    mContext->ClearColor(r, g, b, a);
  }

  void ClearDepth(GLclampf v) const { mContext->ClearDepth(v); }

  void ClearStencil(GLint v) const { mContext->ClearStencil(v); }

  void ColorMask(Maybe<GLuint> i, uint8_t mask) const {
    mContext->ColorMask(i, mask);
  }

  void CompileShader(const ObjectId id) const {
    const auto obj = ById<WebGLShader>(id);
    if (!obj) return;
    mContext->CompileShader(*obj);
  }

  void CullFace(GLenum face) const { mContext->CullFace(face); }

  void DepthFunc(GLenum func) const { mContext->DepthFunc(func); }

  void DepthMask(WebGLboolean b) const { mContext->DepthMask(b); }

  void DepthRange(GLclampf zNear, GLclampf zFar) const {
    mContext->DepthRange(zNear, zFar);
  }

  void DetachShader(const ObjectId prog, const ObjectId shader) const {
    const auto pProg = ById<WebGLProgram>(prog);
    const auto pShader = ById<WebGLShader>(shader);
    if (!pProg || !pShader) return;
    mContext->DetachShader(*pProg, *pShader);
  }

  void Flush() const { mContext->Flush(); }

  void Finish() const { mContext->Finish(); }

  void FramebufferAttach(const GLenum target, const GLenum attachSlot,
                         const GLenum bindImageTarget, const ObjectId id,
                         const GLint mipLevel, const GLint zLayerBase,
                         const GLsizei numViewLayers) const {
    webgl::FbAttachInfo toAttach;
    toAttach.rb = AutoResolve(id);
    toAttach.tex = AutoResolve(id);
    toAttach.mipLevel = mipLevel;
    toAttach.zLayer = zLayerBase;
    if (numViewLayers) {
      toAttach.zLayerCount = numViewLayers;
      toAttach.isMultiview = true;
    }

    mContext->FramebufferAttach(target, attachSlot, bindImageTarget, toAttach);
  }

  void FrontFace(GLenum mode) const { mContext->FrontFace(mode); }

  Maybe<double> GetBufferParameter(GLenum target, GLenum pname) const {
    return mContext->GetBufferParameter(target, pname);
  }

  webgl::CompileResult GetCompileResult(ObjectId id) const {
    const auto obj = ById<WebGLShader>(id);
    if (!obj) return {};
    return mContext->GetCompileResult(*obj);
  }

  GLenum GetError() const { return mContext->GetError(); }

  GLint GetFragDataLocation(ObjectId id, const std::string& name) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return -1;
    return mContext->GetFragDataLocation(*obj, name);
  }

  Maybe<double> GetFramebufferAttachmentParameter(ObjectId id,
                                                  GLenum attachment,
                                                  GLenum pname) const {
    return mContext->GetFramebufferAttachmentParameter(AutoResolve(id),
                                                       attachment, pname);
  }

  webgl::LinkResult GetLinkResult(ObjectId id) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return {};
    return mContext->GetLinkResult(*obj);
  }

  Maybe<double> GetRenderbufferParameter(ObjectId id, GLenum pname) const {
    const auto obj = ById<WebGLRenderbuffer>(id);
    if (!obj) return {};
    return mContext->GetRenderbufferParameter(*obj, pname);
  }

  Maybe<webgl::ShaderPrecisionFormat> GetShaderPrecisionFormat(
      GLenum shaderType, GLenum precisionType) const {
    return mContext->GetShaderPrecisionFormat(shaderType, precisionType);
  }

  webgl::GetUniformData GetUniform(ObjectId id, uint32_t loc) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return {};
    return mContext->GetUniform(*obj, loc);
  }

  void Hint(GLenum target, GLenum mode) const { mContext->Hint(target, mode); }

  void LineWidth(GLfloat width) const { mContext->LineWidth(width); }

  void LinkProgram(const ObjectId id) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return;
    mContext->LinkProgram(*obj);
  }

  void PolygonOffset(GLfloat factor, GLfloat units) const {
    mContext->PolygonOffset(factor, units);
  }

  void SampleCoverage(GLclampf value, bool invert) const {
    mContext->SampleCoverage(value, invert);
  }

  void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) const {
    mContext->Scissor(x, y, width, height);
  }

  // TODO: s/nsAString/std::string/
  void ShaderSource(const ObjectId id, const std::string& source) const {
    const auto obj = ById<WebGLShader>(id);
    if (!obj) return;
    mContext->ShaderSource(*obj, source);
  }

  void StencilFuncSeparate(GLenum face, GLenum func, GLint ref,
                           GLuint mask) const {
    mContext->StencilFuncSeparate(face, func, ref, mask);
  }
  void StencilMaskSeparate(GLenum face, GLuint mask) const {
    mContext->StencilMaskSeparate(face, mask);
  }
  void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
                         GLenum dppass) const {
    mContext->StencilOpSeparate(face, sfail, dpfail, dppass);
  }

  void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) const {
    mContext->Viewport(x, y, width, height);
  }

  // ------------------------- Buffer Objects -------------------------
  void BindBuffer(GLenum target, const ObjectId id) const {
    mContext->BindBuffer(target, AutoResolve(id));
  }

  void BindBufferRange(GLenum target, GLuint index, const ObjectId id,
                       uint64_t offset, uint64_t size) const {
    GetWebGL2Context()->BindBufferRange(target, index, AutoResolve(id), offset,
                                        size);
  }

  void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                         uint64_t readOffset, uint64_t writeOffset,
                         uint64_t size) const {
    GetWebGL2Context()->CopyBufferSubData(readTarget, writeTarget, readOffset,
                                          writeOffset, size);
  }

  bool GetBufferSubData(GLenum target, uint64_t srcByteOffset,
                        const Range<uint8_t>& dest) const {
    return GetWebGL2Context()->GetBufferSubData(target, srcByteOffset, dest);
  }

  void BufferData(GLenum target, const RawBuffer<>& srcData, GLenum usage) const {
    mContext->BufferData(target, srcData.size(), srcData.begin(), usage);
  }

  void BufferData_SizeOnly(GLenum target, size_t byteSize, GLenum usage) const {
    mContext->BufferData(target, byteSize, nullptr, usage);
  }

  void BufferSubData(GLenum target, uint64_t dstByteOffset,
                     const RawBuffer<>& srcData,
                     bool unsynchronized = false) const {
    const auto& range = srcData.Data();
    mContext->BufferSubData(target, dstByteOffset, range.length(),
                            range.begin().get(), unsynchronized);
  }

  // -------------------------- Framebuffer Objects --------------------------
  void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                       GLbitfield mask, GLenum filter) const {
    GetWebGL2Context()->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0,
                                        dstY0, dstX1, dstY1, mask, filter);
  }

  void InvalidateFramebuffer(GLenum target,
                             const RawBuffer<const GLenum>& attachments) const {
    GetWebGL2Context()->InvalidateFramebuffer(target, MakeRange(attachments));
  }

  void InvalidateSubFramebuffer(GLenum target,
                                const RawBuffer<const GLenum>& attachments,
                                GLint x, GLint y, GLsizei width,
                                GLsizei height) const {
    GetWebGL2Context()->InvalidateSubFramebuffer(target, MakeRange(attachments),
                                                 x, y, width, height);
  }

  void ReadBuffer(GLenum mode) const { GetWebGL2Context()->ReadBuffer(mode); }

  // ----------------------- Renderbuffer objects -----------------------
  Maybe<std::vector<int32_t>> GetInternalformatParameter(GLenum target,
                                                         GLenum internalformat,
                                                         GLenum pname) const {
    return GetWebGL2Context()->GetInternalformatParameter(
        target, internalformat, pname);
  }

  void RenderbufferStorageMultisample(ObjectId id, uint32_t samples,
                                      GLenum internalFormat, uint32_t width,
                                      uint32_t height) const {
    const auto obj = ById<WebGLRenderbuffer>(id);
    if (!obj) return;
    mContext->RenderbufferStorageMultisample(*obj, samples, internalFormat,
                                             width, height);
  }

  // --------------------------- Texture objects ---------------------------
  void ActiveTexture(uint32_t texUnit) const {
    mContext->ActiveTexture(texUnit);
  }

  void BindTexture(GLenum texTarget, const ObjectId id) const {
    mContext->BindTexture(texTarget, AutoResolve(id));
  }

  void GenerateMipmap(GLenum texTarget) const {
    mContext->GenerateMipmap(texTarget);
  }

  // CompressedTexSubImage if `sub`
  void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level,
                          GLenum format, const uvec3& offset, const uvec3& size,
                          const RawBuffer<>& src, const uint32_t pboImageSize,
                          const Maybe<uint64_t>& pboOffset) const {
    mContext->CompressedTexImage(sub, imageTarget, level, format, offset, size,
                                 MakeRange(src), pboImageSize, pboOffset);
  }

  // CopyTexSubImage if `!respecFormat`
  void CopyTexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
                    const uvec3& dstOffset, const ivec2& srcOffset,
                    const uvec2& size) const {
    mContext->CopyTexImage(imageTarget, level, respecFormat, dstOffset,
                           srcOffset, size);
  }

  // TexSubImage if `!respecFormat`
  void TexImage(uint32_t level, GLenum respecFormat, const uvec3& offset,
                const webgl::PackingInfo& pi,
                const webgl::TexUnpackBlobDesc& src) const {
    mContext->TexImage(level, respecFormat, offset, pi, src);
  }

  void TexStorage(GLenum texTarget, uint32_t levels, GLenum internalFormat,
                  const uvec3& size) const {
    GetWebGL2Context()->TexStorage(texTarget, levels, internalFormat, size);
  }

  Maybe<double> GetTexParameter(ObjectId id, GLenum pname) const {
    const auto obj = ById<WebGLTexture>(id);
    if (!obj) return {};
    return mContext->GetTexParameter(*obj, pname);
  }

  void TexParameter_base(GLenum texTarget, GLenum pname,
                         const FloatOrInt& param) const {
    mContext->TexParameter_base(texTarget, pname, param);
  }

  // ------------------- Programs and shaders --------------------------------
  void UseProgram(ObjectId id) const { mContext->UseProgram(AutoResolve(id)); }

  bool ValidateProgram(ObjectId id) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return false;
    return mContext->ValidateProgram(*obj);
  }

  // ------------------------ Uniforms and attributes ------------------------

  void UniformData(uint32_t loc, bool transpose,
                   const RawBuffer<webgl::UniformDataVal>& data) const {
    mContext->UniformData(loc, transpose, data.Data());
  }

  void VertexAttrib4T(GLuint index, const webgl::TypedQuad& data) const {
    mContext->VertexAttrib4T(index, data);
  }

  void VertexAttribDivisor(GLuint index, GLuint divisor) const {
    mContext->VertexAttribDivisor(index, divisor);
  }

  Maybe<double> GetIndexedParameter(GLenum target, GLuint index) const {
    return GetWebGL2Context()->GetIndexedParameter(target, index);
  }

  void UniformBlockBinding(const ObjectId id, GLuint uniformBlockIndex,
                           GLuint uniformBlockBinding) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return;
    GetWebGL2Context()->UniformBlockBinding(*obj, uniformBlockIndex,
                                            uniformBlockBinding);
  }

  void EnableVertexAttribArray(GLuint index) const {
    mContext->EnableVertexAttribArray(index);
  }

  void DisableVertexAttribArray(GLuint index) const {
    mContext->DisableVertexAttribArray(index);
  }

  Maybe<double> GetVertexAttrib(GLuint index, GLenum pname) const {
    return mContext->GetVertexAttrib(index, pname);
  }

  void VertexAttribPointer(GLuint index,
                           const webgl::VertAttribPointerDesc& desc) const {
    mContext->VertexAttribPointer(index, desc);
  }

  // --------------------------- Buffer Operations --------------------------
  void ClearBufferTv(GLenum buffer, GLint drawBuffer,
                     const webgl::TypedQuad& data) const {
    GetWebGL2Context()->ClearBufferTv(buffer, drawBuffer, data);
  }

  void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
                     GLint stencil) const {
    GetWebGL2Context()->ClearBufferfi(buffer, drawBuffer, depth, stencil);
  }

  // ------------------------------ Readback -------------------------------
  void ReadPixelsPbo(const webgl::ReadPixelsDesc& desc,
                     const uint64_t offset) const {
    mContext->ReadPixelsPbo(desc, offset);
  }

  webgl::ReadPixelsResult ReadPixelsInto(const webgl::ReadPixelsDesc& desc,
                                         const Range<uint8_t>& dest) const {
    return mContext->ReadPixelsInto(desc, dest);
  }

  // ----------------------------- Sampler -----------------------------------

  void BindSampler(GLuint unit, ObjectId id) const {
    GetWebGL2Context()->BindSampler(unit, AutoResolve(id));
  }

  void SamplerParameteri(ObjectId id, GLenum pname, GLint param) const {
    const auto obj = ById<WebGLSampler>(id);
    if (!obj) return;
    GetWebGL2Context()->SamplerParameteri(*obj, pname, param);
  }

  void SamplerParameterf(ObjectId id, GLenum pname, GLfloat param) const {
    const auto obj = ById<WebGLSampler>(id);
    if (!obj) return;
    GetWebGL2Context()->SamplerParameterf(*obj, pname, param);
  }

  Maybe<double> GetSamplerParameter(ObjectId id, GLenum pname) const {
    const auto obj = ById<WebGLSampler>(id);
    if (!obj) return {};
    return GetWebGL2Context()->GetSamplerParameter(*obj, pname);
  }

  // ------------------------------- GL Sync ---------------------------------

  GLenum ClientWaitSync(ObjectId id, GLbitfield flags, GLuint64 timeout) const {
    const auto obj = ById<WebGLSync>(id);
    if (!obj) return LOCAL_GL_WAIT_FAILED;
    return GetWebGL2Context()->ClientWaitSync(*obj, flags, timeout);
  }

  // -------------------------- Transform Feedback ---------------------------
  void BindTransformFeedback(ObjectId id) const {
    GetWebGL2Context()->BindTransformFeedback(AutoResolve(id));
  }

  void BeginTransformFeedback(GLenum primitiveMode) const {
    GetWebGL2Context()->BeginTransformFeedback(primitiveMode);
  }

  void EndTransformFeedback() const {
    GetWebGL2Context()->EndTransformFeedback();
  }

  void PauseTransformFeedback() const {
    GetWebGL2Context()->PauseTransformFeedback();
  }

  void ResumeTransformFeedback() const {
    GetWebGL2Context()->ResumeTransformFeedback();
  }

  void TransformFeedbackVaryings(ObjectId id,
                                 const std::vector<std::string>& varyings,
                                 GLenum bufferMode) const {
    const auto obj = ById<WebGLProgram>(id);
    if (!obj) return;
    GetWebGL2Context()->TransformFeedbackVaryings(*obj, varyings, bufferMode);
  }

  // -------------------------- Opaque Framebuffers ---------------------------
  void SetFramebufferIsInOpaqueRAF(ObjectId id, bool value) {
    WebGLFramebuffer* fb = AutoResolve(id);
    if (fb) {
      fb->mInOpaqueRAF = value;
    }
  }

  // -------------------------------------------------------------------------
  // Host-side extension methods.  Calls in the client are forwarded to the
  // host. Some extension methods are also available in WebGL2 Contexts.  For
  // them, the final parameter is a boolean indicating if the call originated
  // from an extension.
  // -------------------------------------------------------------------------

  // Misc. Extensions
  void DrawBuffers(const std::vector<GLenum>& buffers) const {
    mContext->DrawBuffers(buffers);
  }

  // VertexArrayObjectEXT
  void BindVertexArray(ObjectId id) const {
    mContext->BindVertexArray(AutoResolve(id));
  }

  // InstancedElementsEXT
  void DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
                           GLsizei primCount) const {
    mContext->DrawArraysInstanced(mode, first, vertCount, primCount);
  }

  void DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
                             WebGLintptr offset, GLsizei primCount) const {
    mContext->DrawElementsInstanced(mode, vertCount, type, offset, primCount);
  }

  // GLQueryEXT
  void BeginQuery(GLenum target, ObjectId id) const {
    const auto obj = ById<WebGLQuery>(id);
    if (!obj) return;
    mContext->BeginQuery(target, *obj);
  }

  void EndQuery(GLenum target) const { mContext->EndQuery(target); }

  void QueryCounter(ObjectId id) const {
    const auto obj = ById<WebGLQuery>(id);
    if (!obj) return;
    mContext->QueryCounter(*obj);
  }

  Maybe<double> GetQueryParameter(ObjectId id, GLenum pname) const {
    const auto obj = ById<WebGLQuery>(id);
    if (!obj) return {};
    return mContext->GetQueryParameter(*obj, pname);
  }

  // WEBGL_provoking_vertex
  void ProvokingVertex(const webgl::ProvokingVertex mode) const {
    mContext->ProvokingVertex(mode);
  }

  // -------------------------------------------------------------------------
  // Client-side methods.  Calls in the Host are forwarded to the client.
  // -------------------------------------------------------------------------
 public:
  void OnLostContext();
  void OnRestoredContext();

 protected:
  WebGL2Context* GetWebGL2Context() const {
    MOZ_RELEASE_ASSERT(mContext->IsWebGL2(), "Requires WebGL2 context");
    return static_cast<WebGL2Context*>(mContext.get());
  }
};

}  // namespace mozilla

#endif  // HOSTWEBGLCONTEXT_H_