Edit

kc3-lang/angle/src/libANGLE/Caps.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-06-06 14:43:30
    Hash : 50c562de
    Message : Re-land: Don't expose non-conformant multisampling modes on GL Re-landing with a fallback for failed internal format queries to work around issue seen on Shield TV. Also fixed wrong handling of integer RG formats in isRequiredRenderbufferFormat. Some NVIDIA GL drivers expose non-conformant multisampling modes. The conformance of multisampling modes can be queried using the extension NV_internalformat_sample_query. Use it to filter out the non-conformant modes from the modes that are exposed by ANGLE. The MAX_SAMPLES value and other similar values stored in caps also need to be lowered to match the maximum number of samples exposed for required formats. There seems to be an NVIDIA driver bug related to querying STENCIL_INDEX8 multisample format. Work around this by querying DEPTH24_STENCIL8 instead. There's also some confusion around whether RGB9_E5 should be renderable. Once the floating point texture extensions got rolled into the core GL spec, it was eventually made clear that RGB9_E5 is intended not to be renderable. The extension specs that predate float textures in the core spec do suggest that it would be renderable, but in practice drivers that advertise the extension strings don't reliably implement RGB9_E5 as renderable. Solve this by disabling it as a renderable format and adding an explanatory comment. BUG=chromium:682815 TEST=angle_end2end_tests, dEQP-GLES31.functional.state_query.internal_format.renderbuffer.* Change-Id: I727f03045a1534d6764b571e6d839243705d25b3 Reviewed-on: https://chromium-review.googlesource.com/551957 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/Caps.cpp
  • //
    // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "libANGLE/Caps.h"
    
    #include "common/debug.h"
    #include "common/angleutils.h"
    
    #include "libANGLE/formatutils.h"
    
    #include "angle_gl.h"
    
    #include <algorithm>
    #include <sstream>
    
    static void InsertExtensionString(const std::string &extension, bool supported, std::vector<std::string> *extensionVector)
    {
        if (supported)
        {
            extensionVector->push_back(extension);
        }
    }
    
    namespace gl
    {
    
    TextureCaps::TextureCaps()
        : texturable(false),
          filterable(false),
          renderable(false),
          sampleCounts()
    {
    }
    
    GLuint TextureCaps::getMaxSamples() const
    {
        return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0;
    }
    
    GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const
    {
        if (requestedSamples == 0)
        {
            return 0;
        }
    
        for (SupportedSampleSet::const_iterator i = sampleCounts.begin(); i != sampleCounts.end(); i++)
        {
            GLuint samples = *i;
            if (samples >= requestedSamples)
            {
                return samples;
            }
        }
    
        return 0;
    }
    
    TextureCaps GenerateMinimumTextureCaps(GLenum sizedInternalFormat,
                                           const Version &clientVersion,
                                           const Extensions &extensions)
    {
        TextureCaps caps;
    
        const InternalFormat &internalFormatInfo = GetSizedInternalFormatInfo(sizedInternalFormat);
        caps.texturable = internalFormatInfo.textureSupport(clientVersion, extensions);
        caps.renderable = internalFormatInfo.renderSupport(clientVersion, extensions);
        caps.filterable = internalFormatInfo.filterSupport(clientVersion, extensions);
    
        caps.sampleCounts.insert(0);
        if (internalFormatInfo.isRequiredRenderbufferFormat(clientVersion))
        {
            if ((clientVersion.major >= 3 && clientVersion.minor >= 1) ||
                (clientVersion.major >= 3 && internalFormatInfo.componentType != GL_UNSIGNED_INT &&
                 internalFormatInfo.componentType != GL_INT))
            {
                caps.sampleCounts.insert(4);
            }
        }
    
        return caps;
    }
    
    void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps)
    {
        mCapsMap[internalFormat] = caps;
    }
    
    void TextureCapsMap::remove(GLenum internalFormat)
    {
        InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat);
        if (i != mCapsMap.end())
        {
            mCapsMap.erase(i);
        }
    }
    
    void TextureCapsMap::clear()
    {
        mCapsMap.clear();
    }
    
    const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const
    {
        static TextureCaps defaultUnsupportedTexture;
        InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat);
        return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture;
    }
    
    TextureCapsMap::const_iterator TextureCapsMap::begin() const
    {
        return mCapsMap.begin();
    }
    
    TextureCapsMap::const_iterator TextureCapsMap::end() const
    {
        return mCapsMap.end();
    }
    
    size_t TextureCapsMap::size() const
    {
        return mCapsMap.size();
    }
    
    TextureCapsMap GenerateMinimumTextureCapsMap(const Version &clientVersion,
                                                 const Extensions &extensions)
    {
        TextureCapsMap capsMap;
    
        for (GLenum internalFormat : GetAllSizedInternalFormats())
        {
            capsMap.insert(internalFormat,
                           GenerateMinimumTextureCaps(internalFormat, clientVersion, extensions));
        }
    
        return capsMap;
    }
    
    Extensions::Extensions()
        : elementIndexUint(false),
          packedDepthStencil(false),
          getProgramBinary(false),
          rgb8rgba8(false),
          textureFormatBGRA8888(false),
          readFormatBGRA(false),
          pixelBufferObject(false),
          mapBuffer(false),
          mapBufferRange(false),
          colorBufferHalfFloat(false),
          textureHalfFloat(false),
          textureHalfFloatLinear(false),
          textureFloat(false),
          textureFloatLinear(false),
          textureRG(false),
          textureCompressionDXT1(false),
          textureCompressionDXT3(false),
          textureCompressionDXT5(false),
          textureCompressionS3TCsRGB(false),
          textureCompressionASTCHDR(false),
          textureCompressionASTCLDR(false),
          compressedETC1RGB8Texture(false),
          sRGB(false),
          depthTextures(false),
          depth32(false),
          textureStorage(false),
          textureNPOT(false),
          drawBuffers(false),
          textureFilterAnisotropic(false),
          maxTextureAnisotropy(0.0f),
          occlusionQueryBoolean(false),
          fence(false),
          timerQuery(false),
          disjointTimerQuery(false),
          queryCounterBitsTimeElapsed(0),
          queryCounterBitsTimestamp(0),
          robustness(false),
          blendMinMax(false),
          framebufferBlit(false),
          framebufferMultisample(false),
          instancedArrays(false),
          packReverseRowOrder(false),
          standardDerivatives(false),
          shaderTextureLOD(false),
          shaderFramebufferFetch(false),
          ARMshaderFramebufferFetch(false),
          NVshaderFramebufferFetch(false),
          fragDepth(false),
          textureUsage(false),
          translatedShaderSource(false),
          fboRenderMipmap(false),
          discardFramebuffer(false),
          debugMarker(false),
          eglImage(false),
          eglImageExternal(false),
          eglImageExternalEssl3(false),
          eglStreamConsumerExternal(false),
          unpackSubimage(false),
          packSubimage(false),
          vertexArrayObject(false),
          debug(false),
          maxDebugMessageLength(0),
          maxDebugLoggedMessages(0),
          maxDebugGroupStackDepth(0),
          maxLabelLength(0),
          noError(false),
          lossyETCDecode(false),
          bindUniformLocation(false),
          syncQuery(false),
          copyTexture(false),
          copyCompressedTexture(false),
          webglCompatibility(false),
          requestExtension(false),
          bindGeneratesResource(false),
          robustClientMemory(false),
          textureSRGBDecode(false),
          sRGBWriteControl(false),
          colorBufferFloatRGB(false),
          colorBufferFloatRGBA(false),
          colorBufferFloat(false),
          multisampleCompatibility(false),
          framebufferMixedSamples(false),
          textureNorm16(false),
          pathRendering(false),
          surfacelessContext(false),
          clientArrays(false),
          robustResourceInitialization(false)
    {
    }
    
    std::vector<std::string> Extensions::getStrings() const
    {
        std::vector<std::string> extensionStrings;
    
        for (const auto &extensionInfo : GetExtensionInfoMap())
        {
            if (this->*(extensionInfo.second.ExtensionsMember))
            {
                extensionStrings.push_back(extensionInfo.first);
            }
        }
    
        return extensionStrings;
    }
    
    Limitations::Limitations()
        : noFrontFacingSupport(false),
          noSampleAlphaToCoverageSupport(false),
          attributeZeroRequiresZeroDivisorInEXT(false),
          noSeparateStencilRefsAndMasks(false),
          shadersRequireIndexedLoopValidation(false),
          noSimultaneousConstantColorAndAlphaBlendFunc(false)
    {
    }
    
    static bool GetFormatSupportBase(const TextureCapsMap &textureCaps,
                                     const GLenum *requiredFormats,
                                     size_t requiredFormatsSize,
                                     bool requiresTexturing,
                                     bool requiresFiltering,
                                     bool requiresRendering)
    {
        for (size_t i = 0; i < requiredFormatsSize; i++)
        {
            const TextureCaps &cap = textureCaps.get(requiredFormats[i]);
    
            if (requiresTexturing && !cap.texturable)
            {
                return false;
            }
    
            if (requiresFiltering && !cap.filterable)
            {
                return false;
            }
    
            if (requiresRendering && !cap.renderable)
            {
                return false;
            }
        }
    
        return true;
    }
    
    template <size_t N>
    static bool GetFormatSupport(const TextureCapsMap &textureCaps,
                                 const GLenum (&requiredFormats)[N],
                                 bool requiresTexturing,
                                 bool requiresFiltering,
                                 bool requiresRendering)
    {
        return GetFormatSupportBase(textureCaps, requiredFormats, N, requiresTexturing,
                                    requiresFiltering, requiresRendering);
    }
    
    // Check for GL_OES_packed_depth_stencil
    static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_DEPTH24_STENCIL8,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, false, false, true);
    }
    
    // Checks for GL_OES_rgb8_rgba8 support
    static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB8, GL_RGBA8,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, true);
    }
    
    // Checks for GL_EXT_texture_format_BGRA8888 support
    static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_BGRA8_EXT,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, true);
    }
    
    // Checks for GL_OES_color_buffer_half_float support
    static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, true);
    }
    
    // Checks for GL_OES_texture_half_float support
    static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB16F, GL_RGBA16F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, false);
    }
    
    // Checks for GL_OES_texture_half_float_linear support
    static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB16F, GL_RGBA16F,
        };
    
        return DetermineHalfFloatTextureSupport(textureCaps) &&
               GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Checks for GL_OES_texture_float support
    static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB32F, GL_RGBA32F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, false);
    }
    
    // Checks for GL_OES_texture_float_linear support
    static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB32F, GL_RGBA32F,
        };
    
        return DetermineFloatTextureSupport(textureCaps) &&
               GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Checks for GL_EXT_texture_rg support
    static bool DetermineRGHalfFloatTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_R16F, GL_RG16F,
        };
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    static bool DetermineRGFloatTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_R32F, GL_RG32F,
        };
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats)
    {
        if (checkHalfFloatFormats && !DetermineRGHalfFloatTextureSupport(textureCaps))
        {
            return false;
        }
    
        if (checkFloatFormats && !DetermineRGFloatTextureSupport(textureCaps))
        {
            return false;
        }
    
        constexpr GLenum requiredFormats[] = {
            GL_R8, GL_RG8,
        };
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_EXT_texture_compression_dxt1
    static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_ANGLE_texture_compression_dxt3
    static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_ANGLE_texture_compression_dxt5
    static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_EXT_texture_compression_s3tc_srgb
    static bool DetermineS3TCsRGBTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
            GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_KHR_texture_compression_astc_hdr and GL_KHR_texture_compression_astc_ldr
    static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_COMPRESSED_RGBA_ASTC_4x4_KHR,           GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
            GL_COMPRESSED_RGBA_ASTC_5x5_KHR,           GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
            GL_COMPRESSED_RGBA_ASTC_6x6_KHR,           GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
            GL_COMPRESSED_RGBA_ASTC_8x6_KHR,           GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
            GL_COMPRESSED_RGBA_ASTC_10x5_KHR,          GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
            GL_COMPRESSED_RGBA_ASTC_10x8_KHR,          GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
            GL_COMPRESSED_RGBA_ASTC_12x10_KHR,         GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,   GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,   GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,   GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,   GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,  GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
            GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_ETC1_RGB8_OES
    static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_ETC1_RGB8_OES,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
    }
    
    // Check for GL_ANGLE_texture_compression_dxt5
    static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFilterFormats[] = {
            GL_SRGB8, GL_SRGB8_ALPHA8,
        };
    
        constexpr GLenum requiredRenderFormats[] = {
            GL_SRGB8_ALPHA8,
        };
    
        return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) &&
               GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true);
    }
    
    // Check for GL_ANGLE_depth_texture
    static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32_OES, GL_DEPTH24_STENCIL8_OES,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, true, true);
    }
    
    // Check for GL_OES_depth32
    static bool DetermineDepth32Support(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_DEPTH_COMPONENT32_OES,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, false, false, true);
    }
    
    // Check for GL_CHROMIUM_color_buffer_float_rgb
    static bool DetermineColorBufferFloatRGBSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGB32F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, true);
    }
    
    // Check for GL_CHROMIUM_color_buffer_float_rgba
    static bool DetermineColorBufferFloatRGBASupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_RGBA32F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, true);
    }
    
    // Check for GL_EXT_color_buffer_float
    static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFormats[] = {
            GL_R16F, GL_RG16F, GL_RGBA16F, GL_R32F, GL_RG32F, GL_RGBA32F, GL_R11F_G11F_B10F,
        };
    
        return GetFormatSupport(textureCaps, requiredFormats, true, false, true);
    }
    
    // Check for GL_EXT_texture_norm16
    static bool DetermineTextureNorm16Support(const TextureCapsMap &textureCaps)
    {
        constexpr GLenum requiredFilterFormats[] = {
            GL_R16_EXT,       GL_RG16_EXT,       GL_RGB16_EXT,       GL_RGBA16_EXT,
            GL_R16_SNORM_EXT, GL_RG16_SNORM_EXT, GL_RGB16_SNORM_EXT, GL_RGBA16_SNORM_EXT,
        };
    
        constexpr GLenum requiredRenderFormats[] = {
            GL_R16_EXT, GL_RG16_EXT, GL_RGBA16_EXT,
        };
    
        return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) &&
               GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true);
    }
    
    void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
    {
        packedDepthStencil = DeterminePackedDepthStencilSupport(textureCaps);
        rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps);
        textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps);
        colorBufferHalfFloat      = DetermineColorBufferHalfFloatSupport(textureCaps);
        textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps);
        textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps);
        textureFloat = DetermineFloatTextureSupport(textureCaps);
        textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps);
        textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat);
        textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
        textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps);
        textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps);
        textureCompressionS3TCsRGB = DetermineS3TCsRGBTextureSupport(textureCaps);
        textureCompressionASTCHDR = DetermineASTCTextureSupport(textureCaps);
        textureCompressionASTCLDR = textureCompressionASTCHDR;
        compressedETC1RGB8Texture = DetermineETC1RGB8TextureSupport(textureCaps);
        sRGB = DetermineSRGBTextureSupport(textureCaps);
        depthTextures = DetermineDepthTextureSupport(textureCaps);
        depth32                   = DetermineDepth32Support(textureCaps);
        colorBufferFloatRGB        = DetermineColorBufferFloatRGBSupport(textureCaps);
        colorBufferFloatRGBA       = DetermineColorBufferFloatRGBASupport(textureCaps);
        colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps);
        textureNorm16             = DetermineTextureNorm16Support(textureCaps);
    }
    
    const ExtensionInfoMap &GetExtensionInfoMap()
    {
        auto buildExtensionInfoMap = []() {
            auto enableableExtension = [](ExtensionInfo::ExtensionBool member) {
                ExtensionInfo info;
                info.Requestable      = true;
                info.ExtensionsMember = member;
                return info;
            };
    
            auto esOnlyExtension = [](ExtensionInfo::ExtensionBool member) {
                ExtensionInfo info;
                info.ExtensionsMember = member;
                return info;
            };
    
            // clang-format off
            ExtensionInfoMap map;
            map["GL_OES_element_index_uint"] = enableableExtension(&Extensions::elementIndexUint);
            map["GL_OES_packed_depth_stencil"] = esOnlyExtension(&Extensions::packedDepthStencil);
            map["GL_OES_get_program_binary"] = esOnlyExtension(&Extensions::getProgramBinary);
            map["GL_OES_rgb8_rgba8"] = esOnlyExtension(&Extensions::rgb8rgba8);
            map["GL_EXT_texture_format_BGRA8888"] = esOnlyExtension(&Extensions::textureFormatBGRA8888);
            map["GL_EXT_read_format_bgra"] = esOnlyExtension(&Extensions::readFormatBGRA);
            map["GL_NV_pixel_buffer_object"] = esOnlyExtension(&Extensions::pixelBufferObject);
            map["GL_OES_mapbuffer"] = esOnlyExtension(&Extensions::mapBuffer);
            map["GL_EXT_map_buffer_range"] = esOnlyExtension(&Extensions::mapBufferRange);
            map["GL_EXT_color_buffer_half_float"] = enableableExtension(&Extensions::colorBufferHalfFloat);
            map["GL_OES_texture_half_float"] = enableableExtension(&Extensions::textureHalfFloat);
            map["GL_OES_texture_half_float_linear"] = enableableExtension(&Extensions::textureHalfFloatLinear);
            map["GL_OES_texture_float"] = enableableExtension(&Extensions::textureFloat);
            map["GL_OES_texture_float_linear"] = enableableExtension(&Extensions::textureFloatLinear);
            map["GL_EXT_texture_rg"] = esOnlyExtension(&Extensions::textureRG);
            map["GL_EXT_texture_compression_dxt1"] = esOnlyExtension(&Extensions::textureCompressionDXT1);
            map["GL_ANGLE_texture_compression_dxt3"] = esOnlyExtension(&Extensions::textureCompressionDXT3);
            map["GL_ANGLE_texture_compression_dxt5"] = esOnlyExtension(&Extensions::textureCompressionDXT5);
            map["GL_EXT_texture_compression_s3tc_srgb"] = esOnlyExtension(&Extensions::textureCompressionS3TCsRGB);
            map["GL_KHR_texture_compression_astc_hdr"] = esOnlyExtension(&Extensions::textureCompressionASTCHDR);
            map["GL_KHR_texture_compression_astc_ldr"] = esOnlyExtension(&Extensions::textureCompressionASTCLDR);
            map["GL_OES_compressed_ETC1_RGB8_texture"] = esOnlyExtension(&Extensions::compressedETC1RGB8Texture);
            map["GL_EXT_sRGB"] = esOnlyExtension(&Extensions::sRGB);
            map["GL_ANGLE_depth_texture"] = esOnlyExtension(&Extensions::depthTextures);
            map["GL_OES_depth32"] = esOnlyExtension(&Extensions::depth32);
            map["GL_EXT_texture_storage"] = esOnlyExtension(&Extensions::textureStorage);
            map["GL_OES_texture_npot"] = enableableExtension(&Extensions::textureNPOT);
            map["GL_EXT_draw_buffers"] = enableableExtension(&Extensions::drawBuffers);
            map["GL_EXT_texture_filter_anisotropic"] = enableableExtension(&Extensions::textureFilterAnisotropic);
            map["GL_EXT_occlusion_query_boolean"] = esOnlyExtension(&Extensions::occlusionQueryBoolean);
            map["GL_NV_fence"] = esOnlyExtension(&Extensions::fence);
            map["GL_ANGLE_timer_query"] = esOnlyExtension(&Extensions::timerQuery);
            map["GL_EXT_disjoint_timer_query"] = esOnlyExtension(&Extensions::disjointTimerQuery);
            map["GL_EXT_robustness"] = esOnlyExtension(&Extensions::robustness);
            map["GL_EXT_blend_minmax"] = esOnlyExtension(&Extensions::blendMinMax);
            map["GL_ANGLE_framebuffer_blit"] = esOnlyExtension(&Extensions::framebufferBlit);
            map["GL_ANGLE_framebuffer_multisample"] = esOnlyExtension(&Extensions::framebufferMultisample);
            map["GL_ANGLE_instanced_arrays"] = esOnlyExtension(&Extensions::instancedArrays);
            map["GL_ANGLE_pack_reverse_row_order"] = esOnlyExtension(&Extensions::packReverseRowOrder);
            map["GL_OES_standard_derivatives"] = enableableExtension(&Extensions::standardDerivatives);
            map["GL_EXT_shader_texture_lod"] = enableableExtension(&Extensions::shaderTextureLOD);
            map["GL_NV_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::NVshaderFramebufferFetch);
            map["GL_ARM_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::ARMshaderFramebufferFetch);
            map["GL_EXT_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::shaderFramebufferFetch);
            map["GL_EXT_frag_depth"] = enableableExtension(&Extensions::fragDepth);
            map["GL_ANGLE_texture_usage"] = esOnlyExtension(&Extensions::textureUsage);
            map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource);
            map["GL_OES_fbo_render_mipmap"] = esOnlyExtension(&Extensions::fboRenderMipmap);
            map["GL_EXT_discard_framebuffer"] = esOnlyExtension(&Extensions::discardFramebuffer);
            map["GL_EXT_debug_marker"] = esOnlyExtension(&Extensions::debugMarker);
            map["GL_OES_EGL_image"] = esOnlyExtension(&Extensions::eglImage);
            map["GL_OES_EGL_image_external"] = esOnlyExtension(&Extensions::eglImageExternal);
            map["GL_OES_EGL_image_external_essl3"] = esOnlyExtension(&Extensions::eglImageExternalEssl3);
            map["GL_NV_EGL_stream_consumer_external"] = esOnlyExtension(&Extensions::eglStreamConsumerExternal);
            map["GL_EXT_unpack_subimage"] = esOnlyExtension(&Extensions::unpackSubimage);
            map["GL_NV_pack_subimage"] = esOnlyExtension(&Extensions::packSubimage);
            map["GL_EXT_color_buffer_float"] = enableableExtension(&Extensions::colorBufferFloat);
            map["GL_OES_vertex_array_object"] = esOnlyExtension(&Extensions::vertexArrayObject);
            map["GL_KHR_debug"] = esOnlyExtension(&Extensions::debug);
            // TODO(jmadill): Enable this when complete.
            //map["GL_KHR_no_error"] = esOnlyExtension(&Extensions::noError);
            map["GL_ANGLE_lossy_etc_decode"] = esOnlyExtension(&Extensions::lossyETCDecode);
            map["GL_CHROMIUM_bind_uniform_location"] = esOnlyExtension(&Extensions::bindUniformLocation);
            map["GL_CHROMIUM_sync_query"] = esOnlyExtension(&Extensions::syncQuery);
            map["GL_CHROMIUM_copy_texture"] = esOnlyExtension(&Extensions::copyTexture);
            map["GL_CHROMIUM_copy_compressed_texture"] = esOnlyExtension(&Extensions::copyCompressedTexture);
            map["GL_ANGLE_webgl_compatibility"] = esOnlyExtension(&Extensions::webglCompatibility);
            map["GL_ANGLE_request_extension"] = esOnlyExtension(&Extensions::requestExtension);
            map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource);
            map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory);
            map["GL_EXT_texture_sRGB_decode"] = esOnlyExtension(&Extensions::textureSRGBDecode);
            map["GL_EXT_sRGB_write_control"] = esOnlyExtension(&Extensions::sRGBWriteControl);
            map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB);
            map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA);
            map["GL_EXT_multisample_compatibility"] = esOnlyExtension(&Extensions::multisampleCompatibility);
            map["GL_CHROMIUM_framebuffer_mixed_samples"] = esOnlyExtension(&Extensions::framebufferMixedSamples);
            map["GL_EXT_texture_norm16"] = esOnlyExtension(&Extensions::textureNorm16);
            map["GL_CHROMIUM_path_rendering"] = esOnlyExtension(&Extensions::pathRendering);
            map["GL_OES_surfaceless_context"] = esOnlyExtension(&Extensions::surfacelessContext);
            map["GL_ANGLE_client_arrays"] = esOnlyExtension(&Extensions::clientArrays);
            map["GL_ANGLE_robust_resource_initialization"] = esOnlyExtension(&Extensions::robustResourceInitialization);
            // clang-format on
    
            return map;
        };
    
        static const ExtensionInfoMap extensionInfo = buildExtensionInfoMap();
        return extensionInfo;
    }
    
    TypePrecision::TypePrecision() : range({{0, 0}}), precision(0)
    {
    }
    
    void TypePrecision::setIEEEFloat()
    {
        range     = {{127, 127}};
        precision = 23;
    }
    
    void TypePrecision::setTwosComplementInt(unsigned int bits)
    {
        range     = {{static_cast<GLint>(bits) - 1, static_cast<GLint>(bits) - 2}};
        precision = 0;
    }
    
    void TypePrecision::setSimulatedFloat(unsigned int r, unsigned int p)
    {
        range     = {{static_cast<GLint>(r), static_cast<GLint>(r)}};
        precision = static_cast<GLint>(p);
    }
    
    void TypePrecision::setSimulatedInt(unsigned int r)
    {
        range     = {{static_cast<GLint>(r), static_cast<GLint>(r)}};
        precision = 0;
    }
    
    void TypePrecision::get(GLint *returnRange, GLint *returnPrecision) const
    {
        std::copy(range.begin(), range.end(), returnRange);
        *returnPrecision = precision;
    }
    
    Caps::Caps()
        : maxElementIndex(0),
          max3DTextureSize(0),
          max2DTextureSize(0),
          maxArrayTextureLayers(0),
          maxLODBias(0),
          maxCubeMapTextureSize(0),
          maxRenderbufferSize(0),
          minAliasedPointSize(0),
          maxAliasedPointSize(0),
          minAliasedLineWidth(0),
          maxAliasedLineWidth(0),
    
          // Table 20.40
          maxDrawBuffers(0),
          maxFramebufferWidth(0),
          maxFramebufferHeight(0),
          maxFramebufferSamples(0),
          maxColorAttachments(0),
          maxViewportWidth(0),
          maxViewportHeight(0),
          maxSampleMaskWords(0),
          maxColorTextureSamples(0),
          maxDepthTextureSamples(0),
          maxIntegerSamples(0),
          maxServerWaitTimeout(0),
    
          // Table 20.41
          maxVertexAttribRelativeOffset(0),
          maxVertexAttribBindings(0),
          maxVertexAttribStride(0),
          maxElementsIndices(0),
          maxElementsVertices(0),
    
          // Table 20.43
          maxVertexAttributes(0),
          maxVertexUniformComponents(0),
          maxVertexUniformVectors(0),
          maxVertexUniformBlocks(0),
          maxVertexOutputComponents(0),
          maxVertexTextureImageUnits(0),
          maxVertexAtomicCounterBuffers(0),
          maxVertexAtomicCounters(0),
          maxVertexImageUniforms(0),
          maxVertexShaderStorageBlocks(0),
    
          // Table 20.44
          maxFragmentUniformComponents(0),
          maxFragmentUniformVectors(0),
          maxFragmentUniformBlocks(0),
          maxFragmentInputComponents(0),
          maxTextureImageUnits(0),
          maxFragmentAtomicCounterBuffers(0),
          maxFragmentAtomicCounters(0),
          maxFragmentImageUniforms(0),
          maxFragmentShaderStorageBlocks(0),
          minProgramTextureGatherOffset(0),
          maxProgramTextureGatherOffset(0),
          minProgramTexelOffset(0),
          maxProgramTexelOffset(0),
    
          // Table 20.45
          maxComputeWorkGroupInvocations(0),
          maxComputeUniformBlocks(0),
          maxComputeTextureImageUnits(0),
          maxComputeSharedMemorySize(0),
          maxComputeUniformComponents(0),
          maxComputeAtomicCounterBuffers(0),
          maxComputeAtomicCounters(0),
          maxComputeImageUniforms(0),
          maxCombinedComputeUniformComponents(0),
          maxComputeShaderStorageBlocks(0),
    
          // Table 20.46
          maxUniformBufferBindings(0),
          maxUniformBlockSize(0),
          uniformBufferOffsetAlignment(0),
          maxCombinedUniformBlocks(0),
          maxCombinedVertexUniformComponents(0),
          maxCombinedFragmentUniformComponents(0),
          maxVaryingComponents(0),
          maxVaryingVectors(0),
          maxCombinedTextureImageUnits(0),
          maxCombinedShaderOutputResources(0),
    
          // Table 20.47
          maxUniformLocations(0),
          maxAtomicCounterBufferBindings(0),
          maxAtomicCounterBufferSize(0),
          maxCombinedAtomicCounterBuffers(0),
          maxCombinedAtomicCounters(0),
          maxImageUnits(0),
          maxCombinedImageUniforms(0),
          maxShaderStorageBufferBindings(0),
          maxShaderStorageBlockSize(0),
          maxCombinedShaderStorageBlocks(0),
          shaderStorageBufferOffsetAlignment(0),
    
          // Table 20.48
          maxTransformFeedbackInterleavedComponents(0),
          maxTransformFeedbackSeparateAttributes(0),
          maxTransformFeedbackSeparateComponents(0),
    
          // Table 20.49
          maxSamples(0)
    
    {
        for (size_t i = 0; i < 3; ++i)
        {
            maxComputeWorkGroupCount[i] = 0;
            maxComputeWorkGroupSize[i]  = 0;
        }
    }
    
    Caps GenerateMinimumCaps(const Version &clientVersion)
    {
        Caps caps;
    
        if (clientVersion >= Version(2, 0))
        {
            // Table 6.18
            caps.max2DTextureSize      = 64;
            caps.maxCubeMapTextureSize = 16;
            caps.maxViewportWidth      = caps.max2DTextureSize;
            caps.maxViewportHeight     = caps.max2DTextureSize;
            caps.minAliasedPointSize   = 1;
            caps.maxAliasedPointSize   = 1;
            caps.minAliasedLineWidth   = 1;
            caps.maxAliasedLineWidth   = 1;
    
            // Table 6.19
            caps.vertexHighpFloat.setSimulatedFloat(62, 16);
            caps.vertexMediumpFloat.setSimulatedFloat(14, 10);
            caps.vertexLowpFloat.setSimulatedFloat(1, 8);
            caps.vertexHighpInt.setSimulatedInt(16);
            caps.vertexMediumpInt.setSimulatedInt(10);
            caps.vertexLowpInt.setSimulatedInt(8);
            caps.fragmentHighpFloat.setSimulatedFloat(62, 16);
            caps.fragmentMediumpFloat.setSimulatedFloat(14, 10);
            caps.fragmentLowpFloat.setSimulatedFloat(1, 8);
            caps.fragmentHighpInt.setSimulatedInt(16);
            caps.fragmentMediumpInt.setSimulatedInt(10);
            caps.fragmentLowpInt.setSimulatedInt(8);
    
            // Table 6.20
            caps.maxVertexAttributes          = 8;
            caps.maxVertexUniformVectors      = 128;
            caps.maxVaryingVectors            = 8;
            caps.maxCombinedTextureImageUnits = 8;
            caps.maxTextureImageUnits         = 8;
            caps.maxFragmentUniformVectors    = 16;
            caps.maxRenderbufferSize          = 1;
        }
    
        if (clientVersion >= Version(3, 0))
        {
            // Table 6.28
            caps.maxElementIndex       = (1 << 24) - 1;
            caps.max3DTextureSize      = 256;
            caps.max2DTextureSize      = 2048;
            caps.maxArrayTextureLayers = 256;
            caps.maxLODBias            = 2.0f;
            caps.maxCubeMapTextureSize = 2048;
            caps.maxRenderbufferSize   = 2048;
            caps.maxDrawBuffers        = 4;
            caps.maxColorAttachments   = 4;
            caps.maxViewportWidth      = caps.max2DTextureSize;
            caps.maxViewportHeight     = caps.max2DTextureSize;
    
            // Table 6.29
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_R11_EAC);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_R11_EAC);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_RG11_EAC);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_RG11_EAC);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_ETC2);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ETC2);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGBA8_ETC2_EAC);
            caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
            caps.vertexHighpFloat.setIEEEFloat();
            caps.vertexHighpInt.setTwosComplementInt(32);
            caps.vertexMediumpInt.setTwosComplementInt(16);
            caps.vertexLowpInt.setTwosComplementInt(8);
            caps.fragmentHighpFloat.setIEEEFloat();
            caps.fragmentHighpInt.setSimulatedInt(32);
            caps.fragmentMediumpInt.setTwosComplementInt(16);
            caps.fragmentLowpInt.setTwosComplementInt(8);
            caps.maxServerWaitTimeout = 0;
    
            // Table 6.31
            caps.maxVertexAttributes        = 16;
            caps.maxVertexUniformComponents = 1024;
            caps.maxVertexUniformVectors    = 256;
            caps.maxVertexUniformBlocks     = 12;
            caps.maxVertexOutputComponents  = 64;
            caps.maxVertexTextureImageUnits = 16;
    
            // Table 6.32
            caps.maxFragmentUniformComponents = 896;
            caps.maxFragmentUniformVectors    = 224;
            caps.maxFragmentUniformBlocks     = 12;
            caps.maxFragmentInputComponents   = 60;
            caps.maxTextureImageUnits         = 16;
            caps.minProgramTexelOffset        = -8;
            caps.maxProgramTexelOffset        = 7;
    
            // Table 6.33
            caps.maxUniformBufferBindings     = 24;
            caps.maxUniformBlockSize          = 16384;
            caps.uniformBufferOffsetAlignment = 256;
            caps.maxCombinedUniformBlocks     = 24;
            caps.maxCombinedVertexUniformComponents =
                caps.maxVertexUniformBlocks * (caps.maxUniformBlockSize / 4) +
                caps.maxVertexUniformComponents;
            caps.maxCombinedFragmentUniformComponents =
                caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) +
                caps.maxFragmentUniformComponents;
            caps.maxVaryingComponents         = 60;
            caps.maxVaryingVectors            = 15;
            caps.maxCombinedTextureImageUnits = 32;
    
            // Table 6.34
            caps.maxTransformFeedbackInterleavedComponents = 64;
            caps.maxTransformFeedbackSeparateAttributes    = 4;
            caps.maxTransformFeedbackSeparateComponents    = 4;
    
            // Table 3.35
            caps.maxSamples = 4;
        }
    
        if (clientVersion >= Version(3, 1))
        {
            // Table 20.40
            caps.maxFramebufferWidth    = 2048;
            caps.maxFramebufferHeight   = 2048;
            caps.maxFramebufferSamples  = 4;
            caps.maxSampleMaskWords     = 1;
            caps.maxColorTextureSamples = 1;
            caps.maxDepthTextureSamples = 1;
            caps.maxIntegerSamples      = 1;
    
            // Table 20.41
            caps.maxVertexAttribRelativeOffset = 2047;
            caps.maxVertexAttribBindings       = 16;
            caps.maxVertexAttribStride         = 2048;
    
            // Table 20.43
            caps.maxVertexAtomicCounterBuffers = 0;
            caps.maxVertexAtomicCounters       = 0;
            caps.maxVertexImageUniforms        = 0;
            caps.maxVertexShaderStorageBlocks  = 0;
    
            // Table 20.44
            caps.maxFragmentUniformComponents    = 1024;
            caps.maxFragmentUniformVectors       = 256;
            caps.maxFragmentAtomicCounterBuffers = 0;
            caps.maxFragmentAtomicCounters       = 0;
            caps.maxFragmentImageUniforms        = 0;
            caps.maxFragmentShaderStorageBlocks  = 0;
            caps.minProgramTextureGatherOffset   = 0;
            caps.maxProgramTextureGatherOffset   = 0;
    
            // Table 20.45
            caps.maxComputeWorkGroupCount       = {{65535, 65535, 65535}};
            caps.maxComputeWorkGroupSize        = {{128, 128, 64}};
            caps.maxComputeWorkGroupInvocations = 12;
            caps.maxComputeUniformBlocks        = 12;
            caps.maxComputeTextureImageUnits    = 16;
            caps.maxComputeSharedMemorySize     = 16384;
            caps.maxComputeUniformComponents    = 1024;
            caps.maxComputeAtomicCounterBuffers = 1;
            caps.maxComputeAtomicCounters       = 8;
            caps.maxComputeImageUniforms        = 4;
            caps.maxCombinedComputeUniformComponents =
                caps.maxComputeUniformBlocks * static_cast<GLuint>(caps.maxUniformBlockSize / 4) +
                caps.maxComputeUniformComponents;
            caps.maxComputeShaderStorageBlocks = 4;
    
            // Table 20.46
            caps.maxUniformBufferBindings = 36;
            caps.maxCombinedFragmentUniformComponents =
                caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) +
                caps.maxFragmentUniformComponents;
            caps.maxCombinedTextureImageUnits     = 48;
            caps.maxCombinedShaderOutputResources = 4;
    
            // Table 20.47
            caps.maxUniformLocations                = 1024;
            caps.maxAtomicCounterBufferBindings     = 1;
            caps.maxAtomicCounterBufferSize         = 32;
            caps.maxCombinedAtomicCounterBuffers    = 1;
            caps.maxCombinedAtomicCounters          = 8;
            caps.maxImageUnits                      = 4;
            caps.maxCombinedImageUniforms           = 4;
            caps.maxShaderStorageBufferBindings     = 4;
            caps.maxShaderStorageBlockSize          = 1 << 27;
            caps.maxCombinedShaderStorageBlocks     = 4;
            caps.shaderStorageBufferOffsetAlignment = 256;
        }
    
        return caps;
    }
    }
    
    namespace egl
    {
    
    Caps::Caps()
        : textureNPOT(false)
    {
    }
    
    DisplayExtensions::DisplayExtensions()
        : createContextRobustness(false),
          d3dShareHandleClientBuffer(false),
          d3dTextureClientBuffer(false),
          surfaceD3DTexture2DShareHandle(false),
          querySurfacePointer(false),
          windowFixedSize(false),
          keyedMutex(false),
          surfaceOrientation(false),
          postSubBuffer(false),
          createContext(false),
          deviceQuery(false),
          image(false),
          imageBase(false),
          imagePixmap(false),
          glTexture2DImage(false),
          glTextureCubemapImage(false),
          glTexture3DImage(false),
          glRenderbufferImage(false),
          getAllProcAddresses(false),
          flexibleSurfaceCompatibility(false),
          directComposition(false),
          createContextNoError(false),
          stream(false),
          streamConsumerGLTexture(false),
          streamConsumerGLTextureYUV(false),
          streamProducerD3DTextureNV12(false),
          createContextWebGLCompatibility(false),
          createContextBindGeneratesResource(false),
          getSyncValues(false),
          swapBuffersWithDamage(false),
          pixelFormatFloat(false),
          surfacelessContext(false),
          displayTextureShareGroup(false),
          createContextClientArrays(false)
    {
    }
    
    std::vector<std::string> DisplayExtensions::getStrings() const
    {
        std::vector<std::string> extensionStrings;
    
        // clang-format off
        //                   | Extension name                                       | Supported flag                    | Output vector   |
        InsertExtensionString("EGL_EXT_create_context_robustness",                   createContextRobustness,            &extensionStrings);
        InsertExtensionString("EGL_ANGLE_d3d_share_handle_client_buffer",            d3dShareHandleClientBuffer,         &extensionStrings);
        InsertExtensionString("EGL_ANGLE_d3d_texture_client_buffer",                 d3dTextureClientBuffer,             &extensionStrings);
        InsertExtensionString("EGL_ANGLE_surface_d3d_texture_2d_share_handle",       surfaceD3DTexture2DShareHandle,     &extensionStrings);
        InsertExtensionString("EGL_ANGLE_query_surface_pointer",                     querySurfacePointer,                &extensionStrings);
        InsertExtensionString("EGL_ANGLE_window_fixed_size",                         windowFixedSize,                    &extensionStrings);
        InsertExtensionString("EGL_ANGLE_keyed_mutex",                               keyedMutex,                         &extensionStrings);
        InsertExtensionString("EGL_ANGLE_surface_orientation",                       surfaceOrientation,                 &extensionStrings);
        InsertExtensionString("EGL_ANGLE_direct_composition",                        directComposition,                  &extensionStrings);
        InsertExtensionString("EGL_NV_post_sub_buffer",                              postSubBuffer,                      &extensionStrings);
        InsertExtensionString("EGL_KHR_create_context",                              createContext,                      &extensionStrings);
        InsertExtensionString("EGL_EXT_device_query",                                deviceQuery,                        &extensionStrings);
        InsertExtensionString("EGL_KHR_image",                                       image,                              &extensionStrings);
        InsertExtensionString("EGL_KHR_image_base",                                  imageBase,                          &extensionStrings);
        InsertExtensionString("EGL_KHR_image_pixmap",                                imagePixmap,                        &extensionStrings);
        InsertExtensionString("EGL_KHR_gl_texture_2D_image",                         glTexture2DImage,                   &extensionStrings);
        InsertExtensionString("EGL_KHR_gl_texture_cubemap_image",                    glTextureCubemapImage,              &extensionStrings);
        InsertExtensionString("EGL_KHR_gl_texture_3D_image",                         glTexture3DImage,                   &extensionStrings);
        InsertExtensionString("EGL_KHR_gl_renderbuffer_image",                       glRenderbufferImage,                &extensionStrings);
        InsertExtensionString("EGL_KHR_get_all_proc_addresses",                      getAllProcAddresses,                &extensionStrings);
        InsertExtensionString("EGL_KHR_stream",                                      stream,                             &extensionStrings);
        InsertExtensionString("EGL_KHR_stream_consumer_gltexture",                   streamConsumerGLTexture,            &extensionStrings);
        InsertExtensionString("EGL_NV_stream_consumer_gltexture_yuv",                streamConsumerGLTextureYUV,         &extensionStrings);
        InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility",            flexibleSurfaceCompatibility,       &extensionStrings);
        InsertExtensionString("EGL_ANGLE_stream_producer_d3d_texture_nv12",          streamProducerD3DTextureNV12,       &extensionStrings);
        InsertExtensionString("EGL_ANGLE_create_context_webgl_compatibility",        createContextWebGLCompatibility,    &extensionStrings);
        InsertExtensionString("EGL_CHROMIUM_create_context_bind_generates_resource", createContextBindGeneratesResource, &extensionStrings);
        InsertExtensionString("EGL_CHROMIUM_sync_control",                           getSyncValues,                      &extensionStrings);
        InsertExtensionString("EGL_EXT_swap_buffers_with_damage",                    swapBuffersWithDamage,              &extensionStrings);
        InsertExtensionString("EGL_EXT_pixel_format_float",                          pixelFormatFloat,                   &extensionStrings);
        InsertExtensionString("EGL_KHR_surfaceless_context",                         surfacelessContext,                 &extensionStrings);
        InsertExtensionString("EGL_ANGLE_display_texture_share_group",               displayTextureShareGroup,           &extensionStrings);
        InsertExtensionString("EGL_ANGLE_create_context_client_arrays",              createContextClientArrays,          &extensionStrings);
        // TODO(jmadill): Enable this when complete.
        //InsertExtensionString("KHR_create_context_no_error",                       createContextNoError,               &extensionStrings);
        // clang-format on
    
        return extensionStrings;
    }
    
    DeviceExtensions::DeviceExtensions()
        : deviceD3D(false)
    {
    }
    
    std::vector<std::string> DeviceExtensions::getStrings() const
    {
        std::vector<std::string> extensionStrings;
    
        //                   | Extension name                                 | Supported flag                | Output vector   |
        InsertExtensionString("EGL_ANGLE_device_d3d",                          deviceD3D,                      &extensionStrings);
    
        return extensionStrings;
    }
    
    ClientExtensions::ClientExtensions()
        : clientExtensions(false),
          platformBase(false),
          platformDevice(false),
          platformANGLE(false),
          platformANGLED3D(false),
          platformANGLEOpenGL(false),
          platformANGLEVulkan(false),
          deviceCreation(false),
          deviceCreationD3D11(false),
          x11Visual(false),
          experimentalPresentPath(false),
          clientGetAllProcAddresses(false),
          displayRobustResourceInitialization(false)
    {
    }
    
    std::vector<std::string> ClientExtensions::getStrings() const
    {
        std::vector<std::string> extensionStrings;
    
        // clang-format off
        //                   | Extension name                         | Supported flag           | Output vector   |
        InsertExtensionString("EGL_EXT_client_extensions",             clientExtensions,          &extensionStrings);
        InsertExtensionString("EGL_EXT_platform_base",                 platformBase,              &extensionStrings);
        InsertExtensionString("EGL_EXT_platform_device",               platformDevice,            &extensionStrings);
        InsertExtensionString("EGL_ANGLE_platform_angle",              platformANGLE,             &extensionStrings);
        InsertExtensionString("EGL_ANGLE_platform_angle_d3d",          platformANGLED3D,          &extensionStrings);
        InsertExtensionString("EGL_ANGLE_platform_angle_opengl",       platformANGLEOpenGL,       &extensionStrings);
        InsertExtensionString("EGL_ANGLE_platform_angle_null",         platformANGLENULL,         &extensionStrings);
        InsertExtensionString("EGL_ANGLE_platform_angle_vulkan",       platformANGLEVulkan,       &extensionStrings);
        InsertExtensionString("EGL_ANGLE_device_creation",             deviceCreation,            &extensionStrings);
        InsertExtensionString("EGL_ANGLE_device_creation_d3d11",       deviceCreationD3D11,       &extensionStrings);
        InsertExtensionString("EGL_ANGLE_x11_visual",                  x11Visual,                 &extensionStrings);
        InsertExtensionString("EGL_ANGLE_experimental_present_path",   experimentalPresentPath,   &extensionStrings);
        InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings);
        InsertExtensionString("EGL_ANGLE_display_robust_resource_initialization", displayRobustResourceInitialization, &extensionStrings);
        // clang-format on
    
        return extensionStrings;
    }
    
    }  // namespace egl