/* -*- 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 WEBGL_FORMATS_H_ #define WEBGL_FORMATS_H_ #include #include #include "mozilla/UniquePtr.h" #include "WebGLTypes.h" namespace mozilla::webgl { using EffectiveFormatValueT = uint8_t; enum class EffectiveFormat : EffectiveFormatValueT { // GLES 3.0.4, p128-129, "Required Texture Formats" // "Texture and renderbuffer color formats" RGBA32I, RGBA32UI, RGBA16I, RGBA16UI, RGBA8, RGBA8I, RGBA8UI, SRGB8_ALPHA8, RGB10_A2, RGB10_A2UI, RGBA4, RGB5_A1, RGB8, RGB565, RG32I, RG32UI, RG16I, RG16UI, RG8, RG8I, RG8UI, R32I, R32UI, R16I, R16UI, R8, R8I, R8UI, // "Texture-only color formats" RGBA32F, RGBA16F, RGBA8_SNORM, RGB32F, RGB32I, RGB32UI, RGB16F, RGB16I, RGB16UI, RGB8_SNORM, RGB8I, RGB8UI, SRGB8, R11F_G11F_B10F, RGB9_E5, RG32F, RG16F, RG8_SNORM, R32F, R16F, R8_SNORM, // "Depth formats" DEPTH_COMPONENT32F, DEPTH_COMPONENT24, DEPTH_COMPONENT16, // "Combined depth+stencil formats" DEPTH32F_STENCIL8, DEPTH24_STENCIL8, // GLES 3.0.4, p205-206, "Required Renderbuffer Formats" STENCIL_INDEX8, //////////////////////////////////// // GLES 3.0.4, p147, table 3.19 // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats" COMPRESSED_R11_EAC, COMPRESSED_SIGNED_R11_EAC, COMPRESSED_RG11_EAC, COMPRESSED_SIGNED_RG11_EAC, COMPRESSED_RGB8_ETC2, COMPRESSED_SRGB8_ETC2, COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, COMPRESSED_RGBA8_ETC2_EAC, COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, // EXT_texture_compression_bptc COMPRESSED_RGBA_BPTC_UNORM, COMPRESSED_SRGB_ALPHA_BPTC_UNORM, COMPRESSED_RGB_BPTC_SIGNED_FLOAT, COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, // EXT_texture_compression_rgtc COMPRESSED_RED_RGTC1, COMPRESSED_SIGNED_RED_RGTC1, COMPRESSED_RG_RGTC2, COMPRESSED_SIGNED_RG_RGTC2, // EXT_texture_compression_s3tc COMPRESSED_RGB_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT3_EXT, COMPRESSED_RGBA_S3TC_DXT5_EXT, // EXT_texture_sRGB COMPRESSED_SRGB_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, // KHR_texture_compression_astc_ldr COMPRESSED_RGBA_ASTC_4x4_KHR, COMPRESSED_RGBA_ASTC_5x4_KHR, COMPRESSED_RGBA_ASTC_5x5_KHR, COMPRESSED_RGBA_ASTC_6x5_KHR, COMPRESSED_RGBA_ASTC_6x6_KHR, COMPRESSED_RGBA_ASTC_8x5_KHR, COMPRESSED_RGBA_ASTC_8x6_KHR, COMPRESSED_RGBA_ASTC_8x8_KHR, COMPRESSED_RGBA_ASTC_10x5_KHR, COMPRESSED_RGBA_ASTC_10x6_KHR, COMPRESSED_RGBA_ASTC_10x8_KHR, COMPRESSED_RGBA_ASTC_10x10_KHR, COMPRESSED_RGBA_ASTC_12x10_KHR, COMPRESSED_RGBA_ASTC_12x12_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, // IMG_texture_compression_pvrtc COMPRESSED_RGB_PVRTC_4BPPV1, COMPRESSED_RGBA_PVRTC_4BPPV1, COMPRESSED_RGB_PVRTC_2BPPV1, COMPRESSED_RGBA_PVRTC_2BPPV1, // OES_compressed_ETC1_RGB8_texture ETC1_RGB8_OES, //////////////////////////////////// // GLES 3.0.4, p128, table 3.12. Luminance8Alpha8, Luminance8, Alpha8, // OES_texture_float Luminance32FAlpha32F, Luminance32F, Alpha32F, // OES_texture_half_float Luminance16FAlpha16F, Luminance16F, Alpha16F, // EXT_texture_norm16 R16, RG16, RGB16, RGBA16, R16_SNORM, RG16_SNORM, RGB16_SNORM, RGBA16_SNORM, MAX, }; enum class UnsizedFormat : uint8_t { R, RG, RGB, RGBA, LA, L, A, D, S, DEPTH_STENCIL, // `DS` is a macro on Solaris. (regset.h) }; // GLES 3.0.4 p114 Table 3.4, p240 enum class ComponentType : uint8_t { Int, // RGBA32I UInt, // RGBA32UI NormInt, // RGBA8_SNORM NormUInt, // RGBA8 Float, // RGBA32F }; const char* ToString(ComponentType); enum class TextureBaseType : uint8_t { Int = uint8_t(ComponentType::Int), UInt = uint8_t(ComponentType::UInt), Float = uint8_t(ComponentType::Float), // Also includes NormU?Int and Depth }; const char* ToString(TextureBaseType); enum class CompressionFamily : uint8_t { ASTC, BPTC, ES3, // ETC2 or EAC ETC1, PVRTC, RGTC, S3TC, }; //////////////////////////////////////////////////////////////////////////////// struct CompressedFormatInfo { const EffectiveFormat effectiveFormat; const uint8_t bytesPerBlock; const uint8_t blockWidth; const uint8_t blockHeight; const CompressionFamily family; }; struct FormatInfo { const EffectiveFormat effectiveFormat; const char* const name; const GLenum sizedFormat; const UnsizedFormat unsizedFormat; const ComponentType componentType; const TextureBaseType baseType; const bool isSRGB; const CompressedFormatInfo* const compression; const uint8_t estimatedBytesPerPixel; // 0 iff bool(compression). // In bits. Iff bool(compression), active channels are 1. const uint8_t r; const uint8_t g; const uint8_t b; const uint8_t a; const uint8_t d; const uint8_t s; ////// std::map copyDecayFormats; const FormatInfo* GetCopyDecayFormat(UnsizedFormat) const; bool IsColorFormat() const { // Alpha is a 'color format' since it's 'color-attachable'. return bool(compression) || bool(r | g | b | a); } }; ////////////////////////////////////////////////////////////////////////////////////////// struct PackingInfoInfo final { uint8_t bytesPerElement = 0; uint8_t elementsPerPixel = 0; // E.g. 1 for LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 bool isPacked = false; static Maybe For(const PackingInfo&); inline uint8_t BytesPerPixel() const { return bytesPerElement * elementsPerPixel; } }; const FormatInfo* GetFormat(EffectiveFormat format); inline uint8_t BytesPerPixel(const PackingInfo& packing) { const auto pii = PackingInfoInfo::For(packing); if (MOZ_LIKELY(pii)) return pii->BytesPerPixel(); gfxCriticalError() << "Bad BytesPerPixel(" << packing << ")"; MOZ_CRASH("Bad `packing`."); } /* GLint ComponentSize(const FormatInfo* format, GLenum component); GLenum ComponentType(const FormatInfo* format); */ //////////////////////////////////////// struct FormatRenderableState final { private: enum class RenderableState { Disabled, Implicit, Explicit, }; public: RenderableState state = RenderableState::Disabled; WebGLExtensionID extid = WebGLExtensionID::Max; static FormatRenderableState Explicit() { return {RenderableState::Explicit}; } static FormatRenderableState Implicit(WebGLExtensionID extid) { return {RenderableState::Implicit, extid}; } bool IsRenderable() const { return state != RenderableState::Disabled; } bool IsExplicit() const { return state == RenderableState::Explicit; } }; struct FormatUsageInfo { const FormatInfo* const format; private: FormatRenderableState renderableState; public: bool isFilterable = false; std::map validUnpacks; const DriverUnpackInfo* idealUnpack = nullptr; const GLint* textureSwizzleRGBA = nullptr; private: mutable bool maxSamplesKnown = false; mutable uint32_t maxSamples = 0; public: static const GLint kLuminanceSwizzleRGBA[4]; static const GLint kAlphaSwizzleRGBA[4]; static const GLint kLumAlphaSwizzleRGBA[4]; explicit FormatUsageInfo(const FormatInfo* const _format) : format(_format) { if (format->IsColorFormat() && format->baseType != TextureBaseType::Float) { maxSamplesKnown = true; } } bool IsRenderable() const { return renderableState.IsRenderable(); } void SetRenderable( const FormatRenderableState& state = FormatRenderableState::Explicit()); bool IsExplicitlyRenderable() const { return renderableState.IsExplicit(); } WebGLExtensionID GetExtensionID() const { MOZ_ASSERT(renderableState.extid != WebGLExtensionID::Max); return renderableState.extid; } bool IsUnpackValid(const PackingInfo& key, const DriverUnpackInfo** const out_value) const; private: void ResolveMaxSamples(gl::GLContext& gl) const; public: uint32_t MaxSamples(gl::GLContext& gl) const { if (!maxSamplesKnown) { ResolveMaxSamples(gl); } return maxSamples; } }; class FormatUsageAuthority { std::map mUsageMap; std::map mRBFormatMap; std::map mSizedTexFormatMap; std::map mUnsizedTexFormatMap; std::set mValidTexInternalFormats; std::set mValidTexUnpackFormats; std::set mValidTexUnpackTypes; public: static UniquePtr CreateForWebGL1(gl::GLContext* gl); static UniquePtr CreateForWebGL2(gl::GLContext* gl); private: FormatUsageAuthority() = default; public: FormatUsageInfo* EditUsage(EffectiveFormat format); const FormatUsageInfo* GetUsage(EffectiveFormat format) const; void AddTexUnpack(FormatUsageInfo* usage, const PackingInfo& pi, const DriverUnpackInfo& dui); bool IsInternalFormatEnumValid(GLenum internalFormat) const; bool AreUnpackEnumsValid(GLenum unpackFormat, GLenum unpackType) const; void AllowRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage, bool expectRenderable = true); void AllowSizedTexFormat(GLenum sizedFormat, const FormatUsageInfo* usage); void AllowUnsizedTexFormat(const PackingInfo& pi, const FormatUsageInfo* usage); const FormatUsageInfo* GetRBUsage(GLenum sizedFormat) const; const FormatUsageInfo* GetSizedTexUsage(GLenum sizedFormat) const; const FormatUsageInfo* GetUnsizedTexUsage(const PackingInfo& pi) const; }; } // namespace mozilla::webgl #endif // WEBGL_FORMATS_H_