Bug 1800301 - Reduce allocs and ptr-chasing in ScopedResolveTexturesForDraw. r=gfx...
[gecko.git] / dom / canvas / WebGLTypes.h
blob0e4a59cd86134021618c466c35ec444b33c6d3c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGLTYPES_H_
7 #define WEBGLTYPES_H_
9 #include <array>
10 #include <limits>
11 #include <string>
12 #include <tuple>
13 #include <type_traits>
14 #include <unordered_map>
15 #include <vector>
17 #include "GLDefs.h"
18 #include "ImageContainer.h"
19 #include "mozilla/Casting.h"
20 #include "mozilla/CheckedInt.h"
21 #include "mozilla/MathAlgorithms.h"
22 #include "mozilla/Range.h"
23 #include "mozilla/RefCounted.h"
24 #include "mozilla/Result.h"
25 #include "mozilla/ResultVariant.h"
26 #include "mozilla/gfx/2D.h"
27 #include "mozilla/gfx/BuildConstants.h"
28 #include "mozilla/gfx/Logging.h"
29 #include "mozilla/gfx/Point.h"
30 #include "mozilla/gfx/Rect.h"
31 #include "mozilla/ipc/Shmem.h"
32 #include "mozilla/layers/LayersSurfaces.h"
33 #include "gfxTypes.h"
35 #include "nsTArray.h"
36 #include "nsString.h"
37 #include "mozilla/dom/WebGLRenderingContextBinding.h"
38 #include "mozilla/ipc/SharedMemoryBasic.h"
39 #include "TiedFields.h"
41 // Manual reflection of WebIDL typedefs that are different from their
42 // OpenGL counterparts.
43 using WebGLsizeiptr = int64_t;
44 using WebGLintptr = int64_t;
45 using WebGLboolean = bool;
47 // -
49 namespace mozilla {
50 namespace gl {
51 class GLContext; // This is going to be needed a lot.
52 } // namespace gl
54 // -
55 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
56 // only!)
58 template <typename DestT>
59 class ForbidNarrowing final {
60 DestT mVal;
62 public:
63 template <typename SrcT>
64 MOZ_IMPLICIT ForbidNarrowing(SrcT val) : mVal(val) {
65 static_assert(
66 std::numeric_limits<SrcT>::min() >= std::numeric_limits<DestT>::min(),
67 "SrcT must be narrower than DestT.");
68 static_assert(
69 std::numeric_limits<SrcT>::max() <= std::numeric_limits<DestT>::max(),
70 "SrcT must be narrower than DestT.");
73 explicit operator DestT() const { return mVal; }
76 inline void* malloc(const ForbidNarrowing<size_t> s) {
77 return ::malloc(size_t(s));
80 inline void* calloc(const ForbidNarrowing<size_t> n,
81 const ForbidNarrowing<size_t> size) {
82 return ::calloc(size_t(n), size_t(size));
85 // -
87 namespace detail {
89 template <typename From>
90 class AutoAssertCastT final {
91 const From mVal;
93 public:
94 explicit AutoAssertCastT(const From val) : mVal(val) {}
96 template <typename To>
97 operator To() const {
98 return AssertedCast<To>(mVal);
102 } // namespace detail
104 template <typename From>
105 inline auto AutoAssertCast(const From val) {
106 return detail::AutoAssertCastT<From>(val);
109 const char* GetEnumName(GLenum val, const char* defaultRet = "<unknown>");
110 std::string EnumString(GLenum val);
112 namespace webgl {
113 template <typename T>
114 struct QueueParamTraits;
115 class TexUnpackBytes;
116 class TexUnpackImage;
117 class TexUnpackSurface;
118 } // namespace webgl
120 class ClientWebGLContext;
121 struct WebGLTexPboOffset;
122 class WebGLTexture;
123 class WebGLBuffer;
124 class WebGLFramebuffer;
125 class WebGLProgram;
126 class WebGLQuery;
127 class WebGLRenderbuffer;
128 class WebGLSampler;
129 class WebGLShader;
130 class WebGLSync;
131 class WebGLTexture;
132 class WebGLTransformFeedback;
133 class WebGLVertexArray;
135 // -
137 class VRefCounted : public RefCounted<VRefCounted> {
138 public:
139 virtual ~VRefCounted() = default;
141 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
142 virtual const char* typeName() const = 0;
143 virtual size_t typeSize() const = 0;
144 #endif
147 // -
150 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
151 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
152 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
153 * desktop OpenGL does not allow that.
155 enum class WebGLVertexAttrib0Status : uint8_t {
156 Default, // default status - no emulation needed
157 EmulatedUninitializedArray, // need an artificial attrib 0 array, but
158 // contents may be left uninitialized
159 EmulatedInitializedArray // need an artificial attrib 0 array, and contents
160 // must be initialized
164 * The formats that may participate, either as source or destination formats,
165 * in WebGL texture conversions. This includes:
166 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
167 * - additional formats provided by extensions, e.g. RGB32F
168 * - additional source formats, depending on browser details, used when
169 * uploading textures from DOM elements. See gfxImageSurface::Format().
171 enum class WebGLTexelFormat : uint8_t {
172 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
173 // image data
174 None,
175 // common value for formats for which format conversions are not supported
176 FormatNotSupportingAnyConversion,
177 // dummy pseudo-format meaning "use the other format".
178 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
179 // is implicitly treated as being RGB8 itself.
180 Auto,
181 // 1-channel formats
183 A16F, // OES_texture_half_float
184 A32F, // OES_texture_float
186 R16F, // OES_texture_half_float
187 R32F, // OES_texture_float
188 // 2-channel formats
189 RA8,
190 RA16F, // OES_texture_half_float
191 RA32F, // OES_texture_float
192 RG8,
193 RG16F,
194 RG32F,
195 // 3-channel formats
196 RGB8,
197 RGB565,
198 RGB11F11F10F,
199 RGB16F, // OES_texture_half_float
200 RGB32F, // OES_texture_float
201 // 4-channel formats
202 RGBA8,
203 RGBA5551,
204 RGBA4444,
205 RGBA16F, // OES_texture_half_float
206 RGBA32F, // OES_texture_float
207 // DOM element source only formats.
208 RGBX8,
209 BGRX8,
210 BGRA8
213 enum class WebGLTexImageFunc : uint8_t {
214 TexImage,
215 TexSubImage,
216 CopyTexImage,
217 CopyTexSubImage,
218 CompTexImage,
219 CompTexSubImage,
222 enum class WebGLTexDimensions : uint8_t { Tex2D, Tex3D };
224 // Please keep extensions in alphabetic order.
225 enum class WebGLExtensionID : uint8_t {
226 ANGLE_instanced_arrays,
227 EXT_blend_minmax,
228 EXT_color_buffer_float,
229 EXT_color_buffer_half_float,
230 EXT_disjoint_timer_query,
231 EXT_float_blend,
232 EXT_frag_depth,
233 EXT_shader_texture_lod,
234 EXT_sRGB,
235 EXT_texture_compression_bptc,
236 EXT_texture_compression_rgtc,
237 EXT_texture_filter_anisotropic,
238 EXT_texture_norm16,
239 MOZ_debug,
240 OES_draw_buffers_indexed,
241 OES_element_index_uint,
242 OES_fbo_render_mipmap,
243 OES_standard_derivatives,
244 OES_texture_float,
245 OES_texture_float_linear,
246 OES_texture_half_float,
247 OES_texture_half_float_linear,
248 OES_vertex_array_object,
249 OVR_multiview2,
250 WEBGL_color_buffer_float,
251 WEBGL_compressed_texture_astc,
252 WEBGL_compressed_texture_etc,
253 WEBGL_compressed_texture_etc1,
254 WEBGL_compressed_texture_pvrtc,
255 WEBGL_compressed_texture_s3tc,
256 WEBGL_compressed_texture_s3tc_srgb,
257 WEBGL_debug_renderer_info,
258 WEBGL_debug_shaders,
259 WEBGL_depth_texture,
260 WEBGL_draw_buffers,
261 WEBGL_explicit_present,
262 WEBGL_lose_context,
266 class UniqueBuffer final {
267 // Like UniquePtr<>, but for void* and malloc/calloc/free.
268 void* mBuffer = nullptr;
270 public:
271 static inline UniqueBuffer Take(void* buffer) {
272 UniqueBuffer ret;
273 ret.mBuffer = buffer;
274 return ret;
277 UniqueBuffer() = default;
279 ~UniqueBuffer() { reset(); }
281 UniqueBuffer(UniqueBuffer&& rhs) { *this = std::move(rhs); }
283 UniqueBuffer& operator=(UniqueBuffer&& rhs) {
284 reset();
285 this->mBuffer = rhs.mBuffer;
286 rhs.mBuffer = nullptr;
287 return *this;
290 explicit operator bool() const { return bool(mBuffer); }
292 void* get() const { return mBuffer; }
294 void reset() {
295 // Believe it or not, when `free` unconditional, it was showing up
296 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
297 // on Aquarium.
298 if (mBuffer) {
299 free(mBuffer);
300 mBuffer = nullptr;
305 namespace webgl {
306 struct FormatUsageInfo;
308 static constexpr GLenum kErrorPerfWarning = 0x10001;
310 struct SampleableInfo final {
311 const char* incompleteReason = nullptr;
312 uint32_t levels = 0;
313 const webgl::FormatUsageInfo* usage = nullptr;
314 bool isDepthTexCompare = false;
316 bool IsComplete() const { return bool(levels); }
319 enum class AttribBaseType : uint8_t {
320 Boolean, // Can convert from anything.
321 Float, // Also includes NormU?Int
322 Int,
323 Uint,
325 webgl::AttribBaseType ToAttribBaseType(GLenum);
326 const char* ToString(AttribBaseType);
328 enum class UniformBaseType : uint8_t {
329 Float,
330 Int,
331 Uint,
333 const char* ToString(UniformBaseType);
335 using ObjectId = uint64_t;
337 enum class BufferKind : uint8_t {
338 Undefined,
339 Index,
340 NonIndex,
343 } // namespace webgl
345 // -
347 struct FloatOrInt final // For TexParameter[fi] and friends.
349 bool isFloat = false;
350 uint8_t padding[3] = {};
351 GLfloat f = 0;
352 GLint i = 0;
354 explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
356 explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
358 auto MutTiedFields() { return std::tie(isFloat, padding, f, i); }
361 // -
363 struct WebGLContextOptions final {
364 bool alpha = true;
365 bool depth = true;
366 bool stencil = false;
367 bool premultipliedAlpha = true;
369 bool antialias = true;
370 bool preserveDrawingBuffer = false;
371 bool failIfMajorPerformanceCaveat = false;
372 bool xrCompatible = false;
374 dom::WebGLPowerPreference powerPreference =
375 dom::WebGLPowerPreference::Default;
376 bool ignoreColorSpace = true;
377 dom::PredefinedColorSpace colorSpace = dom::PredefinedColorSpace::Srgb;
378 bool shouldResistFingerprinting = true;
380 bool enableDebugRendererInfo = false;
382 auto MutTiedFields() {
383 // clang-format off
384 return std::tie(
385 alpha,
386 depth,
387 stencil,
388 premultipliedAlpha,
390 antialias,
391 preserveDrawingBuffer,
392 failIfMajorPerformanceCaveat,
393 xrCompatible,
395 powerPreference,
396 colorSpace,
397 ignoreColorSpace,
398 shouldResistFingerprinting,
400 enableDebugRendererInfo);
401 // clang-format on
404 // -
406 WebGLContextOptions();
407 WebGLContextOptions(const WebGLContextOptions&) = default;
409 using Self = WebGLContextOptions;
410 friend bool operator==(const Self& a, const Self& b) {
411 return TiedFields(a) == TiedFields(b);
413 friend bool operator!=(const Self& a, const Self& b) { return !(a == b); }
416 namespace gfx {
418 inline ColorSpace2 ToColorSpace2(const dom::PredefinedColorSpace cs) {
419 switch (cs) {
420 case dom::PredefinedColorSpace::Srgb:
421 return ColorSpace2::SRGB;
422 case dom::PredefinedColorSpace::Display_p3:
423 return ColorSpace2::DISPLAY_P3;
424 case dom::PredefinedColorSpace::EndGuard_:
425 break;
427 MOZ_CRASH("Exhaustive switch");
430 } // namespace gfx
432 // -
434 template <typename _T>
435 struct avec2 {
436 using T = _T;
438 T x = T();
439 T y = T();
441 auto MutTiedFields() { return std::tie(x, y); }
443 template <typename U, typename V>
444 static Maybe<avec2> From(const U _x, const V _y) {
445 const auto x = CheckedInt<T>(_x);
446 const auto y = CheckedInt<T>(_y);
447 if (!x.isValid() || !y.isValid()) return {};
448 return Some(avec2(x.value(), y.value()));
451 template <typename U>
452 static auto From(const U& val) {
453 return From(val.x, val.y);
455 template <typename U>
456 static auto FromSize(const U& val) {
457 return From(val.width, val.height);
460 avec2() = default;
461 avec2(const T _x, const T _y) : x(_x), y(_y) {}
463 bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
464 bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
466 #define _(OP) \
467 avec2 operator OP(const avec2& rhs) const { \
468 return {x OP rhs.x, y OP rhs.y}; \
470 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
472 _(+)
473 _(-)
474 _(*)
475 _(/)
477 #undef _
479 avec2 Clamp(const avec2& min, const avec2& max) const {
480 return {mozilla::Clamp(x, min.x, max.x), mozilla::Clamp(y, min.y, max.y)};
483 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
484 // helper.
485 avec2 ClampMinMax(const avec2& min, const avec2& max) const {
486 const auto ClampScalar = [](const T v, const T min, const T max) {
487 return std::max(min, std::min(v, max));
489 return {ClampScalar(x, min.x, max.x), ClampScalar(y, min.y, max.y)};
492 template <typename U>
493 U StaticCast() const {
494 return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
498 template <typename T>
499 avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
500 return {std::min(a.x, b.x), std::min(a.y, b.y)};
503 template <typename T>
504 avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
505 return {std::max(a.x, b.x), std::max(a.y, b.y)};
508 // -
510 template <typename _T>
511 struct avec3 {
512 using T = _T;
514 T x = T();
515 T y = T();
516 T z = T();
518 auto MutTiedFields() { return std::tie(x, y, z); }
520 template <typename U, typename V>
521 static Maybe<avec3> From(const U _x, const V _y, const V _z) {
522 const auto x = CheckedInt<T>(_x);
523 const auto y = CheckedInt<T>(_y);
524 const auto z = CheckedInt<T>(_z);
525 if (!x.isValid() || !y.isValid() || !z.isValid()) return {};
526 return Some(avec3(x.value(), y.value(), z.value()));
529 template <typename U>
530 static auto From(const U& val) {
531 return From(val.x, val.y, val.z);
534 avec3() = default;
535 avec3(const T _x, const T _y, const T _z) : x(_x), y(_y), z(_z) {}
537 bool operator==(const avec3& rhs) const {
538 return x == rhs.x && y == rhs.y && z == rhs.z;
540 bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
543 using ivec2 = avec2<int32_t>;
544 using ivec3 = avec3<int32_t>;
545 using uvec2 = avec2<uint32_t>;
546 using uvec3 = avec3<uint32_t>;
548 inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
550 // -
552 namespace webgl {
554 struct PackingInfo final {
555 GLenum format = 0;
556 GLenum type = 0;
558 auto MutTiedFields() { return std::tie(format, type); }
560 using Self = PackingInfo;
561 friend bool operator<(const Self& a, const Self& b) {
562 return TiedFields(a) < TiedFields(b);
564 friend bool operator==(const Self& a, const Self& b) {
565 return TiedFields(a) == TiedFields(b);
568 template <class T>
569 friend T& operator<<(T& s, const PackingInfo& pi) {
570 s << "PackingInfo{format: " << EnumString(pi.format)
571 << ", type: " << EnumString(pi.type) << "}";
572 return s;
576 struct DriverUnpackInfo final {
577 GLenum internalFormat = 0;
578 GLenum unpackFormat = 0;
579 GLenum unpackType = 0;
581 PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
584 // -
586 template <typename E>
587 class EnumMask {
588 public:
589 uint64_t mBits = 0;
591 private:
592 struct BitRef final {
593 EnumMask& bits;
594 const uint64_t mask;
596 explicit operator bool() const { return bits.mBits & mask; }
598 auto& operator=(const bool val) {
599 if (val) {
600 bits.mBits |= mask;
601 } else {
602 bits.mBits &= ~mask;
604 return *this;
608 uint64_t Mask(const E i) const {
609 return uint64_t{1} << static_cast<uint64_t>(i);
612 public:
613 BitRef operator[](const E i) { return {*this, Mask(i)}; }
614 bool operator[](const E i) const { return mBits & Mask(i); }
617 class ExtensionBits : public EnumMask<WebGLExtensionID> {};
619 // -
621 enum class ContextLossReason : uint8_t {
622 None,
623 Manual,
624 Guilty,
627 inline bool ReadContextLossReason(const uint8_t val,
628 ContextLossReason* const out) {
629 if (val > static_cast<uint8_t>(ContextLossReason::Guilty)) {
630 return false;
632 *out = static_cast<ContextLossReason>(val);
633 return true;
636 // -
638 struct InitContextDesc final {
639 bool isWebgl2 = false;
640 bool resistFingerprinting = false;
641 uvec2 size = {};
642 WebGLContextOptions options;
643 uint32_t principalKey = 0;
646 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs = 4;
648 struct Limits final {
649 ExtensionBits supportedExtensions;
651 // WebGL 1
652 uint32_t maxTexUnits = 0;
653 uint32_t maxTex2dSize = 0;
654 uint32_t maxTexCubeSize = 0;
655 uint32_t maxVertexAttribs = 0;
656 uint32_t maxViewportDim = 0;
657 std::array<float, 2> pointSizeRange = {{1, 1}};
658 std::array<float, 2> lineWidthRange = {{1, 1}};
660 // WebGL 2
661 uint32_t maxTexArrayLayers = 0;
662 uint32_t maxTex3dSize = 0;
663 uint32_t maxUniformBufferBindings = 0;
664 uint32_t uniformBufferOffsetAlignment = 0;
666 // Exts
667 bool astcHdr = false;
668 uint32_t maxColorDrawBuffers = 1;
669 uint64_t queryCounterBitsTimeElapsed = 0;
670 uint64_t queryCounterBitsTimestamp = 0;
671 uint32_t maxMultiviewLayers = 0;
674 struct InitContextResult final {
675 std::string error;
676 WebGLContextOptions options;
677 webgl::Limits limits;
678 EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
681 // -
683 struct ErrorInfo final {
684 GLenum type;
685 std::string info;
688 struct ShaderPrecisionFormat final {
689 GLint rangeMin = 0;
690 GLint rangeMax = 0;
691 GLint precision = 0;
694 // -
696 enum class LossStatus {
697 Ready,
699 Lost,
700 LostForever,
701 LostManually,
704 // -
706 struct CompileResult final {
707 bool pending = true;
708 nsCString log;
709 nsCString translatedSource;
710 bool success = false;
713 // -
715 struct OpaqueFramebufferOptions final {
716 bool depthStencil = true;
717 bool antialias = true;
718 uint32_t width = 0;
719 uint32_t height = 0;
722 // -
724 struct SwapChainOptions final {
725 layers::RemoteTextureId remoteTextureId;
726 layers::RemoteTextureOwnerId remoteTextureOwnerId;
727 bool bgra = false;
728 bool forceAsyncPresent = false;
729 // Pad to sizeof(u64):
730 uint16_t padding1 = 0;
731 uint32_t padding2 = 0;
733 auto MutTiedFields() {
734 return std::tie(remoteTextureId, remoteTextureOwnerId, bgra,
735 forceAsyncPresent, padding1, padding2);
739 // -
741 struct ActiveInfo {
742 GLenum elemType = 0; // `type`
743 uint32_t elemCount = 0; // `size`
744 std::string name;
747 struct ActiveAttribInfo final : public ActiveInfo {
748 int32_t location = -1;
749 AttribBaseType baseType = AttribBaseType::Float;
752 struct ActiveUniformInfo final : public ActiveInfo {
753 std::unordered_map<uint32_t, uint32_t>
754 locByIndex; // Uniform array locations are sparse.
755 int32_t block_index = -1;
756 int32_t block_offset = -1; // In block, offset.
757 int32_t block_arrayStride = -1;
758 int32_t block_matrixStride = -1;
759 bool block_isRowMajor = false;
762 struct ActiveUniformBlockInfo final {
763 std::string name;
764 // BLOCK_BINDING is dynamic state
765 uint32_t dataSize = 0;
766 std::vector<uint32_t> activeUniformIndices;
767 bool referencedByVertexShader = false;
768 bool referencedByFragmentShader = false;
771 struct LinkActiveInfo final {
772 std::vector<ActiveAttribInfo> activeAttribs;
773 std::vector<ActiveUniformInfo> activeUniforms;
774 std::vector<ActiveUniformBlockInfo> activeUniformBlocks;
775 std::vector<ActiveInfo> activeTfVaryings;
778 struct LinkResult final {
779 bool pending = true;
780 nsCString log;
781 bool success = false;
782 LinkActiveInfo active;
783 GLenum tfBufferMode = 0;
786 // -
788 /// 4x32-bit primitives, with a type tag.
789 struct TypedQuad final {
790 alignas(alignof(float)) std::array<uint8_t, 4 * sizeof(float)> data = {};
791 webgl::AttribBaseType type = webgl::AttribBaseType::Float;
792 uint8_t padding[3] = {};
794 constexpr auto MutTiedFields() { return std::tie(data, type, padding); }
797 /// [1-16]x32-bit primitives, with a type tag.
798 struct GetUniformData final {
799 alignas(alignof(float)) uint8_t data[4 * 4 * sizeof(float)] = {};
800 GLenum type = 0;
803 struct FrontBufferSnapshotIpc final {
804 uvec2 surfSize = {};
805 Maybe<mozilla::ipc::Shmem> shmem = {};
808 struct ReadPixelsResult {
809 gfx::IntRect subrect = {};
810 size_t byteStride = 0;
813 struct ReadPixelsResultIpc final : public ReadPixelsResult {
814 Maybe<mozilla::ipc::Shmem> shmem = {};
817 struct VertAttribPointerDesc final {
818 bool intFunc = false;
819 uint8_t channels = 4;
820 bool normalized = false;
821 uint8_t byteStrideOrZero = 0;
822 GLenum type = LOCAL_GL_FLOAT;
823 uint64_t byteOffset = 0;
825 auto MutTiedFields() {
826 return std::tie(intFunc, channels, normalized, byteStrideOrZero, type,
827 byteOffset);
831 struct VertAttribPointerCalculated final {
832 uint8_t byteSize = 4 * 4;
833 uint8_t byteStride = 4 * 4; // at-most 255
834 webgl::AttribBaseType baseType = webgl::AttribBaseType::Float;
837 } // namespace webgl
840 * Represents a block of memory that it may or may not own. The
841 * inner data type must be trivially copyable by memcpy.
843 template <typename T = uint8_t>
844 class RawBuffer final {
845 const T* mBegin = nullptr;
846 size_t mLen = 0;
847 UniqueBuffer mOwned;
849 public:
850 using ElementType = T;
853 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
855 explicit RawBuffer(const Range<const T>& data, UniqueBuffer&& owned = {})
856 : mBegin(data.begin().get()),
857 mLen(data.length()),
858 mOwned(std::move(owned)) {}
860 explicit RawBuffer(const size_t len) : mLen(len) {}
862 ~RawBuffer() = default;
864 Range<const T> Data() const { return {mBegin, mLen}; }
865 const auto& begin() const { return mBegin; }
866 const auto& size() const { return mLen; }
868 void Shrink(const size_t newLen) {
869 if (mLen <= newLen) return;
870 mLen = newLen;
873 RawBuffer() = default;
875 RawBuffer(const RawBuffer&) = delete;
876 RawBuffer& operator=(const RawBuffer&) = delete;
878 RawBuffer(RawBuffer&&) = default;
879 RawBuffer& operator=(RawBuffer&&) = default;
882 template <class T>
883 inline Range<T> ShmemRange(const mozilla::ipc::Shmem& shmem) {
884 return {shmem.get<T>(), shmem.Size<T>()};
887 // -
889 template <typename C, typename K>
890 inline auto MaybeFind(C& container, const K& key)
891 -> decltype(&(container.find(key)->second)) {
892 const auto itr = container.find(key);
893 if (itr == container.end()) return nullptr;
894 return &(itr->second);
897 template <typename C, typename K>
898 inline typename C::mapped_type Find(
899 const C& container, const K& key,
900 const typename C::mapped_type notFound = {}) {
901 const auto itr = container.find(key);
902 if (itr == container.end()) return notFound;
903 return itr->second;
906 // -
908 template <typename T, typename U>
909 inline Maybe<T> MaybeAs(const U val) {
910 const auto checked = CheckedInt<T>(val);
911 if (!checked.isValid()) return {};
912 return Some(checked.value());
915 // -
917 inline GLenum ImageToTexTarget(const GLenum imageTarget) {
918 switch (imageTarget) {
919 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
920 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
921 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
922 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
923 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
924 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
925 return LOCAL_GL_TEXTURE_CUBE_MAP;
926 default:
927 return imageTarget;
931 inline bool IsTexTarget3D(const GLenum texTarget) {
932 switch (texTarget) {
933 case LOCAL_GL_TEXTURE_2D_ARRAY:
934 case LOCAL_GL_TEXTURE_3D:
935 return true;
937 default:
938 return false;
942 // -
944 namespace dom {
945 class Element;
946 class ImageBitmap;
947 class ImageData;
948 class OffscreenCanvas;
949 } // namespace dom
951 struct TexImageSource {
952 const dom::ArrayBufferView* mView = nullptr;
953 GLuint mViewElemOffset = 0;
954 GLuint mViewElemLengthOverride = 0;
956 const WebGLintptr* mPboOffset = nullptr;
958 const dom::ImageBitmap* mImageBitmap = nullptr;
959 const dom::ImageData* mImageData = nullptr;
961 const dom::OffscreenCanvas* mOffscreenCanvas = nullptr;
963 const dom::Element* mDomElem = nullptr;
964 ErrorResult* mOut_error = nullptr;
967 namespace webgl {
969 template <class DerivedT>
970 struct DeriveNotEq {
971 bool operator!=(const DerivedT& rhs) const {
972 const auto self = reinterpret_cast<const DerivedT*>(this);
973 return !(*self == rhs);
977 struct PixelPackingState : public DeriveNotEq<PixelPackingState> {
978 uint32_t alignmentInTypeElems = 4; // ALIGNMENT isn't naive byte alignment!
979 uint32_t rowLength = 0;
980 uint32_t imageHeight = 0;
981 uint32_t skipPixels = 0;
982 uint32_t skipRows = 0;
983 uint32_t skipImages = 0;
985 auto MutTiedFields() {
986 return std::tie(alignmentInTypeElems, rowLength, imageHeight, skipPixels,
987 skipRows, skipImages);
990 using Self = PixelPackingState;
991 friend bool operator==(const Self& a, const Self& b) {
992 return TiedFields(a) == TiedFields(b);
995 static void AssertDefaultUnpack(gl::GLContext& gl, const bool isWebgl2) {
996 PixelPackingState{}.AssertCurrentUnpack(gl, isWebgl2);
999 void ApplyUnpack(gl::GLContext&, bool isWebgl2,
1000 const uvec3& uploadSize) const;
1001 bool AssertCurrentUnpack(gl::GLContext&, bool isWebgl2) const;
1004 struct PixelUnpackStateWebgl final : public PixelPackingState {
1005 GLenum colorspaceConversion =
1006 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
1007 bool flipY = false;
1008 bool premultiplyAlpha = false;
1009 bool requireFastPath = false;
1010 uint8_t padding = {};
1012 auto MutTiedFields() {
1013 return std::tuple_cat(PixelPackingState::MutTiedFields(),
1014 std::tie(colorspaceConversion, flipY,
1015 premultiplyAlpha, requireFastPath, padding));
1019 struct ExplicitPixelPackingState final {
1020 struct Metrics final {
1021 uvec3 usedSize = {};
1022 size_t bytesPerPixel = 0;
1024 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1025 // ...aligned to ALIGNMENT.
1026 size_t bytesPerRowStride = 0;
1028 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1029 size_t totalRows = 0;
1031 // This ensures that no one else needs to do CheckedInt math.
1032 size_t totalBytesUsed = 0;
1033 size_t totalBytesStrided = 0;
1036 // It's so important that these aren't modified once evaluated.
1037 const PixelPackingState state;
1038 const Metrics metrics;
1040 static Result<ExplicitPixelPackingState, std::string> ForUseWith(
1041 const PixelPackingState&, GLenum target, const uvec3& subrectSize,
1042 const webgl::PackingInfo&, const Maybe<size_t> bytesPerRowStrideOverride);
1045 struct ReadPixelsDesc final {
1046 ivec2 srcOffset;
1047 uvec2 size;
1048 PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
1049 PixelPackingState packState;
1051 auto MutTiedFields() { return std::tie(srcOffset, size, pi, packState); }
1054 } // namespace webgl
1056 namespace webgl {
1058 struct TexUnpackBlobDesc final {
1059 GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
1060 uvec3 size;
1061 gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
1063 Maybe<RawBuffer<>> cpuData;
1064 Maybe<uint64_t> pboOffset;
1066 Maybe<uvec2> structuredSrcSize;
1067 RefPtr<layers::Image> image;
1068 Maybe<layers::SurfaceDescriptor> sd;
1069 RefPtr<gfx::DataSourceSurface> dataSurf;
1071 webgl::PixelUnpackStateWebgl unpacking;
1072 bool applyUnpackTransforms = true;
1074 // -
1076 auto ExplicitUnpacking(const webgl::PackingInfo& pi,
1077 const Maybe<size_t> bytesPerRowStrideOverride) const {
1078 return ExplicitPixelPackingState::ForUseWith(this->unpacking,
1079 this->imageTarget, this->size,
1080 pi, bytesPerRowStrideOverride);
1083 void Shrink(const webgl::PackingInfo&);
1086 } // namespace webgl
1088 // ---------------------------------------
1089 // MakeRange
1091 template <typename T, size_t N>
1092 inline Range<const T> MakeRange(T (&arr)[N]) {
1093 return {arr, N};
1096 template <typename T>
1097 inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
1098 return {seq.Elements(), seq.Length()};
1101 template <typename T>
1102 inline Range<const T> MakeRange(const RawBuffer<T>& from) {
1103 return from.Data();
1106 // abv = ArrayBufferView
1107 template <typename T>
1108 inline auto MakeRangeAbv(const T& abv)
1109 -> Range<const typename T::element_type> {
1110 abv.ComputeState();
1111 return {abv.Data(), abv.Length()};
1114 // -
1116 constexpr auto kUniversalAlignment = alignof(std::max_align_t);
1118 template <typename T>
1119 inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
1120 MOZ_ASSERT(alignment);
1121 const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
1122 const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
1123 const auto aligned = wholeMultiples * alignment;
1124 return aligned - begin;
1127 template <typename T>
1128 inline size_t ByteSize(const Range<T>& range) {
1129 return range.length() * sizeof(T);
1132 Maybe<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
1133 GLuint elemOffset,
1134 GLuint elemCountOverride);
1136 // -
1138 template <typename T>
1139 RawBuffer<T> RawBufferView(const Range<T>& range) {
1140 return RawBuffer<T>{range};
1143 // -
1145 Maybe<webgl::ErrorInfo> CheckBindBufferRange(
1146 const GLenum target, const GLuint index, const bool isBuffer,
1147 const uint64_t offset, const uint64_t size, const webgl::Limits& limits);
1149 Maybe<webgl::ErrorInfo> CheckFramebufferAttach(const GLenum bindImageTarget,
1150 const GLenum curTexTarget,
1151 const uint32_t mipLevel,
1152 const uint32_t zLayerBase,
1153 const uint32_t zLayerCount,
1154 const webgl::Limits& limits);
1156 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
1157 CheckVertexAttribPointer(bool isWebgl2, const webgl::VertAttribPointerDesc&);
1159 uint8_t ElemTypeComponents(GLenum elemType);
1161 inline std::string ToString(const nsACString& text) {
1162 return {text.BeginReading(), text.Length()};
1165 inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
1166 const RangedPtr<const uint8_t>& srcBytes,
1167 const size_t byteSize) {
1168 // Trigger range asserts
1169 (void)(srcBytes + byteSize);
1170 (void)(destBytes + byteSize);
1172 memcpy(destBytes.get(), srcBytes.get(), byteSize);
1175 template <class T, class U>
1176 inline void Memcpy(const Range<T>* const destRange,
1177 const RangedPtr<U>& srcBegin) {
1178 Memcpy(destRange->begin(), srcBegin, destRange->length());
1180 template <class T, class U>
1181 inline void Memcpy(const RangedPtr<T>* const destBegin,
1182 const Range<U>& srcRange) {
1183 Memcpy(destBegin, srcRange->begin(), srcRange->length());
1186 // -
1188 namespace webgl {
1190 // In theory, this number can be unbounded based on the driver. However, no
1191 // driver appears to expose more than 8. We might as well stop there too, for
1192 // now.
1193 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1194 inline constexpr size_t kMaxDrawBuffers = 8;
1196 union UniformDataVal {
1197 float f32;
1198 int32_t i32;
1199 uint32_t u32;
1202 } // namespace webgl
1204 // -
1206 template <class T, size_t InlineCapacity>
1207 struct InliningAllocator {
1208 using value_type = T;
1210 template <class U>
1211 struct rebind {
1212 typedef InliningAllocator<U, InlineCapacity> other;
1215 private:
1216 std::array<T, InlineCapacity> mInlined = {};
1218 public:
1219 InliningAllocator() = default;
1220 InliningAllocator(const InliningAllocator&) = delete;
1221 InliningAllocator(InliningAllocator&&) = delete;
1222 InliningAllocator& operator=(const InliningAllocator&) = delete;
1223 InliningAllocator& operator=(InliningAllocator&&) = delete;
1225 T* allocate(const size_t n) {
1226 T* p = nullptr;
1227 if (n <= mInlined.size()) {
1228 p = mInlined.data(); // You better be using memmove not memcpy!
1229 } else {
1230 p = new T[n];
1232 return p;
1234 void deallocate(T* const p, size_t) {
1235 if (p != mInlined.data()) {
1236 delete[] p;
1240 template <class T, size_t N>
1241 using inlining_vector = std::vector<T, InliningAllocator<T, N>>;
1243 } // namespace mozilla
1245 #endif