text: /*
   * Copyright 2012 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "src/gpu/gl/GrGLCaps.h"
  
  #include <memory>
  
  #include "include/gpu/GrContextOptions.h"
  #include "src/core/SkCompressedDataUtils.h"
  #include "src/core/SkTSearch.h"
  #include "src/gpu/GrBackendUtils.h"
  #include "src/gpu/GrProgramDesc.h"
  #include "src/gpu/GrShaderCaps.h"
  #include "src/gpu/GrSurfaceProxyPriv.h"
  #include "src/gpu/GrTextureProxyPriv.h"
  #include "src/gpu/SkGr.h"
  #include "src/gpu/gl/GrGLContext.h"
  #include "src/gpu/gl/GrGLRenderTarget.h"
  #include "src/gpu/gl/GrGLTexture.h"
  #include "src/utils/SkJSONWriter.h"
  
  #if defined(SK_BUILD_FOR_IOS)
  #include <TargetConditionals.h>
  #endif
  
  GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
                     const GrGLContextInfo& ctxInfo,
                     const GrGLInterface* glInterface) : INHERITED(contextOptions) {
      fStandard = ctxInfo.standard();
  
      fPackFlipYSupport = false;
      fTextureUsageSupport = false;
      fImagingSupport = false;
      fVertexArrayObjectSupport = false;
      fDebugSupport = false;
      fES2CompatibilitySupport = false;
      fDrawRangeElementsSupport = false;
      fBaseVertexBaseInstanceSupport = false;
      fUseNonVBOVertexAndIndexDynamicData = false;
      fIsCoreProfile = false;
      fBindFragDataLocationSupport = false;
      fRectangleTextureSupport = false;
      fRGBA8888PixelsOpsAreSlow = false;
      fPartialFBOReadIsSlow = false;
      fBindUniformLocationSupport = false;
      fMipmapLevelControlSupport = false;
      fMipmapLodControlSupport = false;
      fRGBAToBGRAReadbackConversionsAreSlow = false;
      fUseBufferDataNullHint = false;
      fDoManualMipmapping = false;
      fClearToBoundaryValuesIsBroken = false;
      fClearTextureSupport = false;
      fDrawArraysBaseVertexIsBroken = false;
      fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = false;
      fUseDrawInsteadOfAllRenderTargetWrites = false;
      fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines = false;
      fDetachStencilFromMSAABuffersBeforeReadPixels = false;
      fDontSetBaseOrMaxLevelForExternalTextures = false;
      fNeverDisableColorWrites = false;
      fMustSetAnyTexParameterToEnableMipmapping = false;
      fAllowBGRA8CopyTexSubImage = false;
      fProgramBinarySupport = false;
      fProgramParameterSupport = false;
      fSamplerObjectSupport = false;
      fUseSamplerObjects = false;
      fTextureSwizzleSupport = false;
      fTiledRenderingSupport = false;
      fFBFetchRequiresEnablePerSample = false;
      fSRGBWriteControl = false;
      fSkipErrorChecks = false;
  
      fShaderCaps.reset(new GrShaderCaps(contextOptions));
  
      this->init(contextOptions, ctxInfo, glInterface);
  }
  
  void GrGLCaps::init(const GrContextOptions& contextOptions,
                      const GrGLContextInfo& ctxInfo,
                      const GrGLInterface* gli) {
      GrGLStandard standard = ctxInfo.standard();
      // standard can be unused (optimzed away) if SK_ASSUME_GL_ES is set
      sk_ignore_unused_variable(standard);
      GrGLVersion version = ctxInfo.version();
  
      if (GR_IS_GR_GL(standard)) {
          GrGLint max;
          GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
          fMaxFragmentUniformVectors = max / 4;
          if (version >= GR_GL_VER(3, 2)) {
              GrGLint profileMask;
              GR_GL_GetIntegerv(gli, GR_GL_CONTEXT_PROFILE_MASK, &profileMask);
              fIsCoreProfile = SkToBool(profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT);
          }
      } else if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS,
                            &fMaxFragmentUniformVectors);
      }
  
      if (fDriverBugWorkarounds.max_fragment_uniform_vectors_32) {
          fMaxFragmentUniformVectors = std::min(fMaxFragmentUniformVectors, 32);
      }
      GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_ATTRIBS, &fMaxVertexAttributes);
  
      if (GR_IS_GR_GL(standard)) {
          fWritePixelsRowBytesSupport = true;
          fReadPixelsRowBytesSupport = true;
          fPackFlipYSupport = false;
      } else if (GR_IS_GR_GL_ES(standard)) {
          fWritePixelsRowBytesSupport =
                  version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_EXT_unpack_subimage");
          fReadPixelsRowBytesSupport =
                  version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_NV_pack_subimage");
          fPackFlipYSupport =
              ctxInfo.hasExtension("GL_ANGLE_pack_reverse_row_order");
      } else if (GR_IS_GR_WEBGL(standard)) {
          // WebGL 2.0 has these
          fWritePixelsRowBytesSupport = version >= GR_GL_VER(2, 0);
          fReadPixelsRowBytesSupport = version >= GR_GL_VER(2, 0);
      }
      if (fDriverBugWorkarounds.pack_parameters_workaround_with_pack_buffer) {
          // In some cases drivers handle copying the last row incorrectly
          // when using GL_PACK_ROW_LENGTH.  Chromium handles this by iterating
          // through every row and conditionally clobbering that value, but
          // Skia already has a scratch buffer workaround when pack row length
          // is not supported, so just use that.
          fReadPixelsRowBytesSupport = false;
      }
  
      fTextureUsageSupport = GR_IS_GR_GL_ES(standard) &&
                             ctxInfo.hasExtension("GL_ANGLE_texture_usage");
  
      if (GR_IS_GR_GL(standard)) {
          fTextureBarrierSupport = version >= GR_GL_VER(4,5) ||
                                   ctxInfo.hasExtension("GL_ARB_texture_barrier") ||
                                   ctxInfo.hasExtension("GL_NV_texture_barrier");
      } else if (GR_IS_GR_GL_ES(standard)) {
          fTextureBarrierSupport = ctxInfo.hasExtension("GL_NV_texture_barrier");
      } // no WebGL support
  
      if (GR_IS_GR_GL(standard)) {
          fSampleLocationsSupport = version >= GR_GL_VER(3,2) ||
                                    ctxInfo.hasExtension("GL_ARB_texture_multisample");
      } else if (GR_IS_GR_GL_ES(standard)) {
          fSampleLocationsSupport = version >= GR_GL_VER(3,1);
      }  // no WebGL support
  
      fImagingSupport = GR_IS_GR_GL(standard) &&
                        ctxInfo.hasExtension("GL_ARB_imaging");
  
      if (((GR_IS_GR_GL(standard) && version >= GR_GL_VER(4,3)) ||
           (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3,0)) ||
           ctxInfo.hasExtension("GL_ARB_invalidate_subdata"))) {
          fInvalidateFBType = kInvalidate_InvalidateFBType;
      } else if (ctxInfo.hasExtension("GL_EXT_discard_framebuffer")) {
          fInvalidateFBType = kDiscard_InvalidateFBType;
      }
  
      // For future reference on Desktop GL, GL_PRIMITIVE_RESTART_FIXED_INDEX appears in 4.3, and
      // GL_PRIMITIVE_RESTART (where the client must call glPrimitiveRestartIndex) appears in 3.1.
      if (GR_IS_GR_GL_ES(standard)) {
          // Primitive restart can cause a 3x slowdown on Adreno. Enable conservatively.
          // FIXME: Primitive restart would likely be a win on iOS if we had an enum value for it.
          if (kARM_GrGLVendor == ctxInfo.vendor()) {
              fUsePrimitiveRestart = version >= GR_GL_VER(3,0);
          }
      }
  
      if (kARM_GrGLVendor == ctxInfo.vendor() ||
          kImagination_GrGLVendor == ctxInfo.vendor() ||
          kQualcomm_GrGLVendor == ctxInfo.vendor() ) {
          fPreferFullscreenClears = true;
      }
  
      if (GR_IS_GR_GL(standard)) {
          fVertexArrayObjectSupport = version >= GR_GL_VER(3, 0) ||
                                      ctxInfo.hasExtension("GL_ARB_vertex_array_object") ||
                                      ctxInfo.hasExtension("GL_APPLE_vertex_array_object");
      } else if (GR_IS_GR_GL_ES(standard)) {
          fVertexArrayObjectSupport = version >= GR_GL_VER(3, 0) ||
                                      ctxInfo.hasExtension("GL_OES_vertex_array_object");
      } else if (GR_IS_GR_WEBGL(standard)) {
          fVertexArrayObjectSupport = version >= GR_GL_VER(2, 0) ||
                                      ctxInfo.hasExtension("GL_OES_vertex_array_object") ||
                                      ctxInfo.hasExtension("OES_vertex_array_object");
      }
  
      if (GR_IS_GR_GL(standard) && version >= GR_GL_VER(4,3)) {
          fDebugSupport = true;
      } else if (GR_IS_GR_GL_ES(standard)) {
          fDebugSupport = ctxInfo.hasExtension("GL_KHR_debug");
      } // no WebGL support
  
      if (GR_IS_GR_GL(standard)) {
          fES2CompatibilitySupport = ctxInfo.hasExtension("GL_ARB_ES2_compatibility");
      }
      else if (GR_IS_GR_GL_ES(standard)) {
          fES2CompatibilitySupport = true;
      } else if (GR_IS_GR_WEBGL(standard)) {
          fES2CompatibilitySupport = true;
      }
  
      if (GR_IS_GR_GL(standard)) {
          fMultisampleDisableSupport = true;
      } else if (GR_IS_GR_GL_ES(standard)) {
          fMultisampleDisableSupport = ctxInfo.hasExtension("GL_EXT_multisample_compatibility");
      } // no WebGL support
  
      if (GR_IS_GR_GL(standard)) {
          // 3.1 has draw_instanced but not instanced_arrays, for the time being we only care about
          // instanced arrays, but we could make this more granular if we wanted
          fDrawInstancedSupport =
                  version >= GR_GL_VER(3, 2) ||
                  (ctxInfo.hasExtension("GL_ARB_draw_instanced") &&
                   ctxInfo.hasExtension("GL_ARB_instanced_arrays"));
      } else if (GR_IS_GR_GL_ES(standard)) {
          fDrawInstancedSupport =
                  version >= GR_GL_VER(3, 0) ||
                  (ctxInfo.hasExtension("GL_EXT_draw_instanced") &&
                   ctxInfo.hasExtension("GL_EXT_instanced_arrays"));
      }  else if (GR_IS_GR_WEBGL(standard)) {
          // WebGL 2.0 has DrawArraysInstanced and drawElementsInstanced
          fDrawInstancedSupport = version >= GR_GL_VER(2, 0);
      }
  
      if (GR_IS_GR_GL(standard)) {
          if (version >= GR_GL_VER(3, 0)) {
              fBindFragDataLocationSupport = true;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (version >= GR_GL_VER(3, 0) && ctxInfo.hasExtension("GL_EXT_blend_func_extended")) {
              fBindFragDataLocationSupport = true;
          }
      } // no WebGL support
  
      fBindUniformLocationSupport = ctxInfo.hasExtension("GL_CHROMIUM_bind_uniform_location");
  
      if (GR_IS_GR_GL(standard)) {
          if (version >= GR_GL_VER(3, 1) || ctxInfo.hasExtension("GL_ARB_texture_rectangle") ||
              ctxInfo.hasExtension("GL_ANGLE_texture_rectangle")) {
              fRectangleTextureSupport = true;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          fRectangleTextureSupport = ctxInfo.hasExtension("GL_ARB_texture_rectangle") ||
                                     ctxInfo.hasExtension("GL_ANGLE_texture_rectangle");
      } // no WebGL support
  
      // GrCaps defaults fClampToBorderSupport to true, so disable when unsupported
      if (GR_IS_GR_GL(standard)) {
          // Clamp to border added in 1.3
          if (version < GR_GL_VER(1, 3) && !ctxInfo.hasExtension("GL_ARB_texture_border_clamp")) {
              fClampToBorderSupport = false;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          // GLES didn't have clamp to border until 3.2, but provides several alternative extensions
          if (version < GR_GL_VER(3, 2) && !ctxInfo.hasExtension("GL_EXT_texture_border_clamp") &&
              !ctxInfo.hasExtension("GL_NV_texture_border_clamp") &&
              !ctxInfo.hasExtension("GL_OES_texture_border_clamp")) {
              fClampToBorderSupport = false;
          }
      } else if (GR_IS_GR_WEBGL(standard)) {
          // WebGL appears to only have REPEAT, CLAMP_TO_EDGE and MIRRORED_REPEAT
          fClampToBorderSupport = false;
      }
  
      if (GR_IS_GR_GL(standard)) {
          if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) {
              fTextureSwizzleSupport = true;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (version >= GR_GL_VER(3,0)) {
              fTextureSwizzleSupport = true;
          }
      } // no WebGL support
  
      if (GR_IS_GR_GL(standard)) {
          fMipmapLevelControlSupport = true;
          fMipmapLodControlSupport = true;
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (version >= GR_GL_VER(3,0)) {
              fMipmapLevelControlSupport = true;
              fMipmapLodControlSupport = true;
          }
      } // no WebGL support
  
  #ifdef SK_BUILD_FOR_WIN
      // We're assuming that on Windows Chromium we're using ANGLE.
      bool isANGLE = kANGLE_GrGLDriver == ctxInfo.driver() ||
                     kChromium_GrGLDriver == ctxInfo.driver();
      // Angle has slow read/write pixel paths for 32bit RGBA (but fast for BGRA).
      fRGBA8888PixelsOpsAreSlow = isANGLE;
      // On DX9 ANGLE reading a partial FBO is slow. TODO: Check whether this is still true and
      // check DX11 ANGLE.
      fPartialFBOReadIsSlow = isANGLE;
  #endif
  
      bool isMESA = kMesa_GrGLDriver == ctxInfo.driver();
      bool isMAC = false;
  #ifdef SK_BUILD_FOR_MAC
      isMAC = true;
  #endif
  
      // Both mesa and mac have reduced performance if reading back an RGBA framebuffer as BGRA or
      // vis-versa.
      fRGBAToBGRAReadbackConversionsAreSlow = isMESA || isMAC;
  
      // Chrome's command buffer will zero out a buffer if null is passed to glBufferData to
      // avoid letting an application see uninitialized memory.
      if (GR_IS_GR_GL(standard) || GR_IS_GR_GL_ES(standard)) {
          fUseBufferDataNullHint = kChromium_GrGLDriver != ctxInfo.driver();
      } else if (GR_IS_GR_WEBGL(standard)) {
          // WebGL spec explicitly disallows null values.
          fUseBufferDataNullHint = false;
      }
  
      if (GR_IS_GR_GL(standard)) {
          fClearTextureSupport = (version >= GR_GL_VER(4,4) ||
                                  ctxInfo.hasExtension("GL_ARB_clear_texture"));
      } else if (GR_IS_GR_GL_ES(standard)) {
          fClearTextureSupport = ctxInfo.hasExtension("GL_EXT_clear_texture");
      }  // no WebGL support
  
  #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
      fSupportsAHardwareBufferImages = true;
  #endif
  
      if (GR_IS_GR_GL(standard)) {
          fSRGBWriteControl = version >= GR_GL_VER(3, 0) ||
                              ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") ||
                              ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB");
      } else if (GR_IS_GR_GL_ES(standard)) {
          // ES through 3.2 requires EXT_srgb_write_control to support toggling
          // sRGB writing for destinations.
          fSRGBWriteControl = ctxInfo.hasExtension("GL_EXT_sRGB_write_control");
      }  // No WebGL support
  
      fSkipErrorChecks = ctxInfo.driver() == kChromium_GrGLDriver;
      if (GR_IS_GR_WEBGL(standard)) {
          // Error checks are quite costly in webgl, especially in Chrome.
          fSkipErrorChecks = true;
      }
  
      // When we are abandoning the context we cannot call into GL thus we should skip any sync work.
      fMustSyncGpuDuringAbandon = false;
  
      /**************************************************************************
      * GrShaderCaps fields
      **************************************************************************/
  
      // This must be called after fCoreProfile is set on the GrGLCaps
      this->initGLSL(ctxInfo, gli);
      GrShaderCaps* shaderCaps = fShaderCaps.get();
  
      // Enable supported shader-related caps
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fDualSourceBlendingSupport =
                  (version >= GR_GL_VER(3, 3) ||
                   ctxInfo.hasExtension("GL_ARB_blend_func_extended")) &&
                  ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
  
          shaderCaps->fShaderDerivativeSupport = true;
  
          // we don't support GL_ARB_geometry_shader4, just GL 3.2+ GS
          shaderCaps->fGeometryShaderSupport = version >= GR_GL_VER(3, 2) &&
              ctxInfo.glslGeneration() >= k150_GrGLSLGeneration;
          if (shaderCaps->fGeometryShaderSupport) {
              if (ctxInfo.glslGeneration() >= k400_GrGLSLGeneration) {
                  shaderCaps->fGSInvocationsSupport = true;
              } else if (ctxInfo.hasExtension("GL_ARB_gpu_shader5")) {
                  shaderCaps->fGSInvocationsSupport = true;
                  shaderCaps->fGSInvocationsExtensionString = "GL_ARB_gpu_shader5";
              }
          }
  
          shaderCaps->fIntegerSupport = version >= GR_GL_VER(3, 0) &&
              ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard)) {
          shaderCaps->fDualSourceBlendingSupport = ctxInfo.hasExtension("GL_EXT_blend_func_extended");
  
          shaderCaps->fShaderDerivativeSupport = version >= GR_GL_VER(3, 0) ||
              ctxInfo.hasExtension("GL_OES_standard_derivatives");
  
          // Mali and early Adreno both have support for geometry shaders, but they appear to be
          // implemented in software. In practice with ccpr, they are slower than the backup impl that
          // only uses vertex shaders.
          if (kARM_GrGLVendor != ctxInfo.vendor() &&
              kAdreno3xx_GrGLRenderer != ctxInfo.renderer() &&
              kAdreno4xx_other_GrGLRenderer != ctxInfo.renderer()) {
  
              if (version >= GR_GL_VER(3,2)) {
                  shaderCaps->fGeometryShaderSupport = true;
              } else if (ctxInfo.hasExtension("GL_EXT_geometry_shader")) {
                  shaderCaps->fGeometryShaderSupport = true;
                  shaderCaps->fGeometryShaderExtensionString = "GL_EXT_geometry_shader";
              }
              shaderCaps->fGSInvocationsSupport = shaderCaps->fGeometryShaderSupport;
          }
  
          shaderCaps->fIntegerSupport = version >= GR_GL_VER(3, 0) &&
              ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // We use this value for GLSL ES 3.0.
      } else if (GR_IS_GR_WEBGL(standard)) {
          shaderCaps->fShaderDerivativeSupport = version >= GR_GL_VER(2, 0) ||
                                                 ctxInfo.hasExtension("GL_OES_standard_derivatives") ||
                                                 ctxInfo.hasExtension("OES_standard_derivatives");
          shaderCaps->fIntegerSupport = (version >= GR_GL_VER(2, 0));
      }
  
      if (ctxInfo.hasExtension("GL_NV_conservative_raster")) {
          fConservativeRasterSupport = true;
      }
  
      if (GR_IS_GR_GL(standard)) {
          fWireframeSupport = true;
      }
  
      // Protect ourselves against tracking huge amounts of texture state.
      static const uint8_t kMaxSaneSamplers = 32;
      GrGLint maxSamplers;
      GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxSamplers);
      shaderCaps->fMaxFragmentSamplers = std::min<GrGLint>(kMaxSaneSamplers, maxSamplers);
  
      // SGX and Mali GPUs have tiled architectures that have trouble with frequently changing VBOs.
      // We've measured a performance increase using non-VBO vertex data for dynamic content on these
      // GPUs. Perhaps we should read the renderer string and limit this decision to specific GPU
      // families rather than basing it on the vendor alone.
      // The Chrome command buffer blocks the use of client side buffers (but may emulate VBOs with
      // them). Client side buffers are not allowed in core profiles.
      if (GR_IS_GR_GL(standard) || GR_IS_GR_GL_ES(standard)) {
          if (ctxInfo.driver() != kChromium_GrGLDriver && !fIsCoreProfile &&
              (ctxInfo.vendor() == kARM_GrGLVendor || ctxInfo.vendor() == kImagination_GrGLVendor ||
               ctxInfo.vendor() == kQualcomm_GrGLVendor)) {
              fPreferClientSideDynamicBuffers = true;
          }
      } // No client side arrays in WebGL https://www.khronos.org/registry/webgl/specs/1.0/#6.2
  
      if (!contextOptions.fAvoidStencilBuffers) {
          // To reduce surface area, if we avoid stencil buffers, we also disable MSAA.
          this->initFSAASupport(contextOptions, ctxInfo, gli);
          this->initStencilSupport(ctxInfo);
      }
  
      // Setup blit framebuffer
      if (GR_IS_GR_GL(standard)) {
          if (version >= GR_GL_VER(3,0) ||
              ctxInfo.hasExtension("GL_ARB_framebuffer_object") ||
              ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
              fBlitFramebufferFlags = 0;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (version >= GR_GL_VER(3, 0)) {
              fBlitFramebufferFlags = kNoFormatConversionForMSAASrc_BlitFramebufferFlag |
                                      kNoMSAADst_BlitFramebufferFlag |
                                      kRectsMustMatchForMSAASrc_BlitFramebufferFlag;
          } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample") ||
                     ctxInfo.hasExtension("GL_ANGLE_framebuffer_blit")) {
              // The CHROMIUM extension uses the ANGLE version of glBlitFramebuffer and includes its
              // limitations.
              fBlitFramebufferFlags = kNoScalingOrMirroring_BlitFramebufferFlag |
                                      kResolveMustBeFull_BlitFrambufferFlag |
                                      kNoMSAADst_BlitFramebufferFlag |
                                      kNoFormatConversion_BlitFramebufferFlag |
                                      kRectsMustMatchForMSAASrc_BlitFramebufferFlag;
          }
      } // No WebGL 1.0 support for BlitFramebuffer
  
      this->initBlendEqationSupport(ctxInfo);
  
      if (GR_IS_GR_GL(standard)) {
          fMapBufferFlags = kCanMap_MapFlag; // we require VBO support and the desktop VBO
                                              // extension includes glMapBuffer.
          if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_map_buffer_range")) {
              fMapBufferFlags |= kSubset_MapFlag;
              fMapBufferType = kMapBufferRange_MapBufferType;
          } else {
              fMapBufferType = kMapBuffer_MapBufferType;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          // Unextended GLES2 doesn't have any buffer mapping.
          fMapBufferFlags = kNone_MapBufferType;
          if (ctxInfo.hasExtension("GL_CHROMIUM_map_sub")) {
              fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag;
              fMapBufferType = kChromium_MapBufferType;
          } else if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_EXT_map_buffer_range")) {
              fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag;
              fMapBufferType = kMapBufferRange_MapBufferType;
          } else if (ctxInfo.hasExtension("GL_OES_mapbuffer")) {
              fMapBufferFlags = kCanMap_MapFlag;
              fMapBufferType = kMapBuffer_MapBufferType;
          }
      } else if (GR_IS_GR_WEBGL(standard)) {
          // explicitly removed https://www.khronos.org/registry/webgl/specs/2.0/#5.14
          fMapBufferFlags = kNone_MapBufferType;
      }
  
      if (GR_IS_GR_GL(standard)) {
          if (version >= GR_GL_VER(2, 1) || ctxInfo.hasExtension("GL_ARB_pixel_buffer_object") ||
              ctxInfo.hasExtension("GL_EXT_pixel_buffer_object")) {
              fTransferFromBufferToTextureSupport = true;
              fTransferFromSurfaceToBufferSupport = true;
              fTransferBufferType = TransferBufferType::kARB_PBO;
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (version >= GR_GL_VER(3, 0) ||
              (ctxInfo.hasExtension("GL_NV_pixel_buffer_object") &&
               // GL_EXT_unpack_subimage needed to support subtexture rectangles
               ctxInfo.hasExtension("GL_EXT_unpack_subimage"))) {
              fTransferFromBufferToTextureSupport = true;
              fTransferFromSurfaceToBufferSupport = true;
              if (version < GR_GL_VER(3, 0)) {
                  fTransferBufferType = TransferBufferType::kNV_PBO;
              } else {
                  fTransferBufferType = TransferBufferType::kARB_PBO;
              }
  // TODO: get transfer buffers working in Chrome
  //        } else if (ctxInfo.hasExtension("GL_CHROMIUM_pixel_transfer_buffer_object")) {
  //            fTransferFromBufferToTextureSupport = false;
  //            fTransferFromSurfaceToBufferSupport = false;
  //            fTransferBufferType = TransferBufferType::kChromium;
          }
      } // no WebGL support
  
      // On many GPUs, map memory is very expensive, so we effectively disable it here by setting the
      // threshold to the maximum unless the client gives us a hint that map memory is cheap.
      if (fBufferMapThreshold < 0) {
  #if 0
          // We think mapping on Chromium will be cheaper once we know ahead of time how much space
          // we will use for all GrMeshDrawOps. Right now we might wind up mapping a large buffer and
          // using a small subset.
          fBufferMapThreshold = kChromium_GrGLDriver == ctxInfo.driver() ? 0 : SK_MaxS32;
  #else
          fBufferMapThreshold = SK_MaxS32;
  #endif
      }
  
      if (GR_IS_GR_GL(standard)) {
          fNPOTTextureTileSupport = true;
          fMipmapSupport = true;
      } else if (GR_IS_GR_GL_ES(standard)) {
          // Unextended ES2 supports NPOT textures with clamp_to_edge and non-mip filters only
          // ES3 has no limitations.
          fNPOTTextureTileSupport = version >= GR_GL_VER(3,0) ||
                                    ctxInfo.hasExtension("GL_OES_texture_npot");
          // ES2 supports MIP mapping for POT textures but our caps don't allow for limited MIP
          // support. The OES extension or ES 3.0 allow for MIPS on NPOT textures. So, apparently,
          // does the undocumented GL_IMG_texture_npot extension. This extension does not seem to
          // to alllow arbitrary wrap modes, however.
          fMipmapSupport = fNPOTTextureTileSupport || ctxInfo.hasExtension("GL_IMG_texture_npot");
      } else if (GR_IS_GR_WEBGL(standard)) {
          // Texture access works in the WebGL 2.0 API as in the OpenGL ES 3.0 API
          fNPOTTextureTileSupport = version >= GR_GL_VER(2,0);
          // All mipmapping and all wrapping modes are supported for non-power-of-
          // two images [in WebGL 2.0].
          fMipmapSupport = fNPOTTextureTileSupport;
      }
  
      GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_SIZE, &fMaxTextureSize);
  
      if (fDriverBugWorkarounds.max_texture_size_limit_4096) {
          fMaxTextureSize = std::min(fMaxTextureSize, 4096);
      }
  
      GR_GL_GetIntegerv(gli, GR_GL_MAX_RENDERBUFFER_SIZE, &fMaxRenderTargetSize);
      fMaxPreferredRenderTargetSize = fMaxRenderTargetSize;
  
      if (kARM_GrGLVendor == ctxInfo.vendor()) {
          // On Mali G71, RT's above 4k have been observed to incur a performance cost.
          fMaxPreferredRenderTargetSize = std::min(4096, fMaxPreferredRenderTargetSize);
      }
  
      fGpuTracingSupport = ctxInfo.hasExtension("GL_EXT_debug_marker");
  
      // Disable scratch texture reuse on Mali and Adreno devices
      fReuseScratchTextures = kARM_GrGLVendor != ctxInfo.vendor();
  
  #if 0
      fReuseScratchBuffers = kARM_GrGLVendor != ctxInfo.vendor() &&
                             kQualcomm_GrGLVendor != ctxInfo.vendor();
  #endif
  
      if (ctxInfo.hasExtension("GL_EXT_window_rectangles")) {
          GR_GL_GetIntegerv(gli, GR_GL_MAX_WINDOW_RECTANGLES, &fMaxWindowRectangles);
      }
  
  #ifdef SK_BUILD_FOR_WIN
      // On ANGLE deferring flushes can lead to GPU starvation
      fPreferVRAMUseOverFlushes = !isANGLE;
  #endif
  
      if (kChromium_GrGLDriver == ctxInfo.driver()) {
          fMustClearUploadedBufferData = true;
      }
  
      // In a WASM build on Firefox, we see warnings like
      // WebGL warning: texSubImage2D: This operation requires zeroing texture data. This is slow.
      // WebGL warning: texSubImage2D: Texture has not been initialized prior to a partial upload,
      //                forcing the browser to clear it. This may be slow.
      // Setting the initial clear seems to make those warnings go away and offers a substantial
      // boost in performance in Firefox. Chrome sees a more modest increase.
      if (GR_IS_GR_WEBGL(standard)) {
          fShouldInitializeTextures = true;
      }
  
      if (GR_IS_GR_GL(standard)) {
          // ARB allows mixed size FBO attachments, EXT does not.
          if (version >= GR_GL_VER(3, 0) ||
              ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
              fOversizedStencilSupport = true;
          } else {
              SkASSERT(ctxInfo.hasExtension("GL_EXT_framebuffer_object"));
          }
      } else if (GR_IS_GR_GL_ES(standard)) {
          // ES 3.0 supports mixed size FBO attachments, 2.0 does not.
          fOversizedStencilSupport = version >= GR_GL_VER(3, 0);
      } else if (GR_IS_GR_WEBGL(standard)) {
          // WebGL 1.0 has some constraints for FBO attachments:
          // https://www.khronos.org/registry/webgl/specs/1.0/index.html#6.6
          // These constraints "no longer apply in WebGL 2"
          fOversizedStencilSupport = version >= GR_GL_VER(2, 0);
      }
  
      if (GR_IS_GR_GL(standard)) {
          fBaseVertexBaseInstanceSupport = version >= GR_GL_VER(4,2) ||
                                           ctxInfo.hasExtension("GL_ARB_base_instance");
          if (fBaseVertexBaseInstanceSupport) {
              fNativeDrawIndirectSupport = version >= GR_GL_VER(4,0) ||
                                           ctxInfo.hasExtension("GL_ARB_draw_indirect");
              if (version >= GR_GL_VER(4,3) || ctxInfo.hasExtension("GL_ARB_multi_draw_indirect")) {
                  fMultiDrawType = MultiDrawType::kMultiDrawIndirect;
              }
          }
          fDrawRangeElementsSupport = version >= GR_GL_VER(2,0);
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (ctxInfo.hasExtension("GL_ANGLE_base_vertex_base_instance")) {
              fBaseVertexBaseInstanceSupport = true;
              fNativeDrawIndirectSupport = true;
              fMultiDrawType = MultiDrawType::kANGLEOrWebGL;
              // The indirect structs need to reside in CPU memory for the ANGLE version.
              fUseClientSideIndirectBuffers = true;
          } else {
              fBaseVertexBaseInstanceSupport = ctxInfo.hasExtension("GL_EXT_base_instance");
              if (fBaseVertexBaseInstanceSupport) {
                  fNativeDrawIndirectSupport = (version >= GR_GL_VER(3,1));
                  if (ctxInfo.hasExtension("GL_EXT_multi_draw_indirect")) {
                      fMultiDrawType = MultiDrawType::kMultiDrawIndirect;
                  }
              }
          }
          fDrawRangeElementsSupport = version >= GR_GL_VER(3,0);
      } else if (GR_IS_GR_WEBGL(standard)) {
          fBaseVertexBaseInstanceSupport = ctxInfo.hasExtension(
                  "WEBGL_draw_instanced_base_vertex_base_instance");
          if (fBaseVertexBaseInstanceSupport && ctxInfo.hasExtension(
                  "GL_WEBGL_multi_draw_instanced_base_vertex_base_instance")) {
              fNativeDrawIndirectSupport = true;
              fMultiDrawType = MultiDrawType::kANGLEOrWebGL;
          }
          // The indirect structs need to reside in CPU memory for the WebGL version.
          fUseClientSideIndirectBuffers = true;
          fDrawRangeElementsSupport = version >= GR_GL_VER(2,0);
      }
  
      // We prefer GL sync objects but also support NV_fence_sync. The former can be
      // used to implements GrFence and GrSemaphore. The latter only implements GrFence.
      // TODO: support CHROMIUM_sync_point and maybe KHR_fence_sync
      if (GR_IS_GR_WEBGL(standard)) {
          // Only in WebGL 2.0
          fSemaphoreSupport = fFenceSyncSupport = version >= GR_GL_VER(2, 0);
          fFenceType = FenceType::kSyncObject;
      } else if (GR_IS_GR_GL(standard) &&
                 (version >= GR_GL_VER(3, 2) || ctxInfo.hasExtension("GL_ARB_sync"))) {
          fSemaphoreSupport = fFenceSyncSupport = true;
          fFenceType = FenceType::kSyncObject;
      } else if (GR_IS_GR_GL_ES(standard) &&
                 (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_APPLE_sync"))) {
          fSemaphoreSupport = fFenceSyncSupport = true;
          fFenceType = FenceType::kSyncObject;
      } else if (ctxInfo.hasExtension("GL_NV_fence")) {
          // This extension can exist in GL and GL ES. We have it last because we prefer the
          // standard GLsync object implementation which also supports GPU semaphore semantics.
          fFenceSyncSupport = true;
          fFenceType = FenceType::kNVFence;
      }
  
      // Safely moving textures between contexts requires semaphores.
      fCrossContextTextureSupport = fSemaphoreSupport;
  
      // Half float vertex attributes requires GL3 or ES3
      // It can also work with OES_VERTEX_HALF_FLOAT, but that requires a different enum.
      if (GR_IS_GR_GL(standard)) {
          fHalfFloatVertexAttributeSupport = (version >= GR_GL_VER(3, 0));
      } else if (GR_IS_GR_GL_ES(standard)) {
          fHalfFloatVertexAttributeSupport = (version >= GR_GL_VER(3, 0));
      } else if (GR_IS_GR_WEBGL(standard)) {
          // This appears to be supported in 2.0, looking at the spec.
          fHalfFloatVertexAttributeSupport = (version >= GR_GL_VER(2, 0));
      }
  
      fDynamicStateArrayGeometryProcessorTextureSupport = true;
  
      if (GR_IS_GR_GL(standard)) {
          fProgramBinarySupport = (version >= GR_GL_VER(4, 1));
          fProgramParameterSupport = (version >= GR_GL_VER(4, 1));
      } else if (GR_IS_GR_GL_ES(standard)) {
          fProgramBinarySupport =
                  (version >= GR_GL_VER(3, 0)) || ctxInfo.hasExtension("GL_OES_get_program_binary");
          fProgramParameterSupport = (version >= GR_GL_VER(3, 0));
      } // Explicitly not supported in WebGL 2.0
        // https://www.khronos.org/registry/webgl/specs/2.0/#5.4
      if (fProgramBinarySupport) {
          GrGLint count;
          GR_GL_GetIntegerv(gli, GR_GL_NUM_PROGRAM_BINARY_FORMATS, &count);
          fProgramBinarySupport = count > 0;
      }
      if (GR_IS_GR_GL(standard)) {
          fSamplerObjectSupport =
                  version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_sampler_objects");
      } else if (GR_IS_GR_GL_ES(standard)) {
          fSamplerObjectSupport = version >= GR_GL_VER(3,0);
      } else if (GR_IS_GR_WEBGL(standard)) {
          fSamplerObjectSupport = version >= GR_GL_VER(2,0);
      }
      // We currently use sampler objects whenever they are available.
      fUseSamplerObjects = fSamplerObjectSupport;
  
      if (GR_IS_GR_GL_ES(standard)) {
          fTiledRenderingSupport = ctxInfo.hasExtension("GL_QCOM_tiled_rendering");
      }
  
      if (kARM_GrGLVendor == ctxInfo.vendor()) {
          fShouldCollapseSrcOverToSrcWhenAble = true;
      }
  
      FormatWorkarounds formatWorkarounds;
  
      if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
          this->applyDriverCorrectnessWorkarounds(ctxInfo, contextOptions, gli, shaderCaps,
                                                  &formatWorkarounds);
      }
  
      // Requires msaa support, ES compatibility have already been detected.
      this->initFormatTable(ctxInfo, gli, formatWorkarounds);
  
      this->finishInitialization(contextOptions);
  
      // For now these two are equivalent but we could have dst read in shader via some other method.
      shaderCaps->fDstReadInShaderSupport = shaderCaps->fFBFetchSupport;
  }
  
  const char* get_glsl_version_decl_string(GrGLStandard standard, GrGLSLGeneration generation,
                                           bool isCoreProfile) {
      if (GR_IS_GR_GL(standard)) {
          switch (generation) {
              case k110_GrGLSLGeneration:
                  return "#version 110\n";
              case k130_GrGLSLGeneration:
                  return "#version 130\n";
              case k140_GrGLSLGeneration:
                  return "#version 140\n";
              case k150_GrGLSLGeneration:
                  if (isCoreProfile) {
                      return "#version 150\n";
                  } else {
                      return "#version 150 compatibility\n";
                  }
              case k330_GrGLSLGeneration:
                  if (isCoreProfile) {
                      return "#version 330\n";
                  } else {
                      return "#version 330 compatibility\n";
                  }
              case k400_GrGLSLGeneration:
                  if (isCoreProfile) {
                      return "#version 400\n";
                  } else {
                      return "#version 400 compatibility\n";
                  }
              case k420_GrGLSLGeneration:
                  if (isCoreProfile) {
                      return "#version 420\n";
                  } else {
                      return "#version 420 compatibility\n";
                  }
              default:
                  break;
          }
      } else if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          switch (generation) {
              case k110_GrGLSLGeneration:
                  // ES2s shader language is based on version 1.20 but is version
                  // 1.00 of the ES language.
                  return "#version 100\n";
              case k330_GrGLSLGeneration:
                  return "#version 300 es\n";
              case k310es_GrGLSLGeneration:
                  return "#version 310 es\n";
              case k320es_GrGLSLGeneration:
                  return "#version 320 es\n";
              default:
                  break;
          }
      }
      return "<no version>";
  }
  
  bool is_float_fp32(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli, GrGLenum precision) {
      if (GR_IS_GR_GL(ctxInfo.standard()) &&
          ctxInfo.version() < GR_GL_VER(4,1) &&
          !ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
          // We're on a desktop GL that doesn't have precision info. Assume they're all 32bit float.
          return true;
      }
      // glGetShaderPrecisionFormat doesn't accept GL_GEOMETRY_SHADER as a shader type. Hopefully the
      // geometry shaders don't have lower precision than vertex and fragment.
      for (GrGLenum shader : {GR_GL_FRAGMENT_SHADER, GR_GL_VERTEX_SHADER}) {
          GrGLint range[2];
          GrGLint bits;
          GR_GL_GetShaderPrecisionFormat(gli, shader, precision, range, &bits);
          if (range[0] < 127 || range[1] < 127 || bits < 23) {
              return false;
          }
      }
      return true;
  }
  
  void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
      GrGLStandard standard = ctxInfo.standard();
      GrGLVersion version = ctxInfo.version();
  
      /**************************************************************************
      * Caps specific to GrShaderCaps
      **************************************************************************/
  
      GrShaderCaps* shaderCaps = fShaderCaps.get();
      shaderCaps->fGLSLGeneration = ctxInfo.glslGeneration();
      if (GR_IS_GR_GL_ES(standard)) {
          // fFBFetchRequiresEnablePerSample is not a shader cap but is initialized below to keep it
          // with related FB fetch logic.
          if (ctxInfo.hasExtension("GL_EXT_shader_framebuffer_fetch")) {
              shaderCaps->fFBFetchNeedsCustomOutput = (version >= GR_GL_VER(3, 0));
              shaderCaps->fFBFetchSupport = true;
              shaderCaps->fFBFetchColorName = "gl_LastFragData[0]";
              shaderCaps->fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch";
              fFBFetchRequiresEnablePerSample = false;
          } else if (ctxInfo.hasExtension("GL_NV_shader_framebuffer_fetch")) {
              // Actually, we haven't seen an ES3.0 device with this extension yet, so we don't know.
              shaderCaps->fFBFetchNeedsCustomOutput = false;
              shaderCaps->fFBFetchSupport = true;
              shaderCaps->fFBFetchColorName = "gl_LastFragData[0]";
              shaderCaps->fFBFetchExtensionString = "GL_NV_shader_framebuffer_fetch";
              fFBFetchRequiresEnablePerSample = false;
          } else if (ctxInfo.hasExtension("GL_ARM_shader_framebuffer_fetch")) {
              // The arm extension also requires an additional flag which we will set onResetContext.
              shaderCaps->fFBFetchNeedsCustomOutput = false;
              shaderCaps->fFBFetchSupport = true;
              shaderCaps->fFBFetchColorName = "gl_LastFragColorARM";
              shaderCaps->fFBFetchExtensionString = "GL_ARM_shader_framebuffer_fetch";
              fFBFetchRequiresEnablePerSample = true;
          }
          shaderCaps->fUsesPrecisionModifiers = true;
      } else if (GR_IS_GR_GL(standard)) {
          if (ctxInfo.hasExtension("GL_EXT_shader_framebuffer_fetch")) {
              shaderCaps->fFBFetchNeedsCustomOutput = (version >= GR_GL_VER(3, 0));
              shaderCaps->fFBFetchSupport = true;
              shaderCaps->fFBFetchColorName = "gl_LastFragData[0]";
              shaderCaps->fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch";
              fFBFetchRequiresEnablePerSample = false;
          }
      } else if (GR_IS_GR_WEBGL(standard)) {
          shaderCaps->fUsesPrecisionModifiers = true;
      }
  
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fFlatInterpolationSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          shaderCaps->fFlatInterpolationSupport =
              ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // This is the value for GLSL ES 3.0.
      } // not sure for WebGL
  
      // Flat interpolation appears to be slow on Qualcomm GPUs (tested Adreno 405 and 530). ANGLE
      // Avoid on ANGLE too, it inserts a geometry shader into the pipeline to implement flat interp.
      shaderCaps->fPreferFlatInterpolation = shaderCaps->fFlatInterpolationSupport &&
                                             kQualcomm_GrGLVendor != ctxInfo.vendor() &&
                                             kANGLE_GrGLDriver != ctxInfo.driver();
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fNoPerspectiveInterpolationSupport =
              ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (ctxInfo.hasExtension("GL_NV_shader_noperspective_interpolation") &&
              ctxInfo.glslGeneration() >= k330_GrGLSLGeneration /* GLSL ES 3.0 */) {
              shaderCaps->fNoPerspectiveInterpolationSupport = true;
              shaderCaps->fNoPerspectiveInterpolationExtensionString =
                  "GL_NV_shader_noperspective_interpolation";
          }
      }  // Not sure for WebGL
  
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fSampleMaskSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard)) {
          if (ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) {
              shaderCaps->fSampleMaskSupport = true;
          } else if (ctxInfo.hasExtension("GL_OES_sample_variables")) {
              shaderCaps->fSampleMaskSupport = true;
              shaderCaps->fSampleVariablesExtensionString = "GL_OES_sample_variables";
          }
      }
  
      bool hasTessellationSupport = false;
      if (GR_IS_GR_GL(standard)) {
          hasTessellationSupport = version >= GR_GL_VER(4,0) ||
                                   ctxInfo.hasExtension("GL_ARB_tessellation_shader");
      } else if (version >= GR_GL_VER(3,2)) {
          hasTessellationSupport = true;
      } else if (ctxInfo.hasExtension("GL_OES_tessellation_shader")) {
          hasTessellationSupport = true;
          shaderCaps->fTessellationExtensionString = "GL_OES_tessellation_shader";
      }
      if (hasTessellationSupport) {
          GR_GL_GetIntegerv(gli, GR_GL_MAX_TESS_GEN_LEVEL_OES,
                            &shaderCaps->fMaxTessellationSegments);
          // Just in case a driver returns a negative number?
          shaderCaps->fMaxTessellationSegments = std::max(0, shaderCaps->fMaxTessellationSegments);
      }
  
      shaderCaps->fVersionDeclString = get_glsl_version_decl_string(standard,
                                                                    shaderCaps->fGLSLGeneration,
                                                                    fIsCoreProfile);
  
      if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          if (k110_GrGLSLGeneration == shaderCaps->fGLSLGeneration) {
              shaderCaps->fShaderDerivativeExtensionString = "GL_OES_standard_derivatives";
          }
      } // WebGL might have to check for OES_standard_derivatives
  
      // Frag Coords Convention support is not part of ES
      if (GR_IS_GR_GL(standard) &&
          (ctxInfo.glslGeneration() >= k150_GrGLSLGeneration ||
           ctxInfo.hasExtension("GL_ARB_fragment_coord_conventions"))) {
          shaderCaps->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions";
      }
  
      if (GR_IS_GR_GL_ES(standard)) {
          shaderCaps->fSecondaryOutputExtensionString = "GL_EXT_blend_func_extended";
      }
  
      if (ctxInfo.hasExtension("GL_OES_EGL_image_external")) {
          if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
              shaderCaps->fExternalTextureSupport = true;
              shaderCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external";
          } else if (ctxInfo.hasExtension("GL_OES_EGL_image_external_essl3") ||
                     ctxInfo.hasExtension("OES_EGL_image_external_essl3")) {
              // At least one driver has been found that has this extension without the "GL_" prefix.
              shaderCaps->fExternalTextureSupport = true;
              shaderCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external_essl3";
          }
      }
  
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fVertexIDSupport = true;
      } else if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          // Desktop GLSL 3.30 == ES GLSL 3.00.
          shaderCaps->fVertexIDSupport = ctxInfo.glslGeneration() >= k330_GrGLSLGeneration;
      }
  
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fFPManipulationSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard) || GR_IS_GR_WEBGL(standard)) {
          shaderCaps->fFPManipulationSupport = ctxInfo.glslGeneration() >= k310es_GrGLSLGeneration;
      }
  
      shaderCaps->fFloatIs32Bits = is_float_fp32(ctxInfo, gli, GR_GL_HIGH_FLOAT);
      shaderCaps->fHalfIs32Bits = is_float_fp32(ctxInfo, gli, GR_GL_MEDIUM_FLOAT);
      shaderCaps->fHasLowFragmentPrecision = kMali4xx_GrGLRenderer == ctxInfo.renderer();
  
      if (GR_IS_GR_GL(standard)) {
          shaderCaps->fBuiltinFMASupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration;
      } else if (GR_IS_GR_GL_ES(standard)) {
          shaderCaps->fBuiltinFMASupport = ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration;
      }
  
      shaderCaps->fBuiltinDeterminantSupport = ctxInfo.glslGeneration() >= k150_GrGLSLGeneration;
  
      if (GR_IS_GR_WEBGL(standard)) {
        // WebGL 1.0 doesn't support do-while loops.
        shaderCaps->fCanUseDoLoops = version >= GR_GL_VER(2, 0);
      }
  }
  
  void GrGLCaps::initFSAASupport(const GrContextOptions& contextOptions,
                                 const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
      if (ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") ||
          ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_mixed_samples")) {
          fMixedSamplesSupport = true;
      }
  
      if (GR_IS_GR_GL(ctxInfo.standard())) {
          if (ctxInfo.version() >= GR_GL_VER(3,0) ||
              ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
              fMSFBOType = kStandard_MSFBOType;
          } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") &&
                     ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
              fMSFBOType = kStandard_MSFBOType;
          }
      } else if (GR_IS_GR_GL_ES(ctxInfo.standard())) {
          // We prefer multisampled-render-to-texture extensions over ES3 MSAA because we've observed
          // ES3 driver bugs on at least one device with a tiled GPU (N10).
          if (ctxInfo.hasExtension("GL_EXT_multisampled_render_to_texture")) {
              fMSFBOType = kES_EXT_MsToTexture_MSFBOType;
              fMSAAResolvesAutomatically = true;
          } else if (ctxInfo.hasExtension("GL_IMG_multisampled_render_to_texture")) {
              fMSFBOType = kES_IMG_MsToTexture_MSFBOType;
              fMSAAResolvesAutomatically = true;
          } else if (ctxInfo.version() >= GR_GL_VER(3,0)) {
              fMSFBOType = kStandard_MSFBOType;
          } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
              fMSFBOType = kStandard_MSFBOType;
          } else if (ctxInfo.hasExtension("GL_ANGLE_framebuffer_multisample")) {
              fMSFBOType = kStandard_MSFBOType;
          } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
              fMSFBOType = kES_Apple_MSFBOType;
          }
      } else if (GR_IS_GR_WEBGL(ctxInfo.standard())) {
          // No support in WebGL 1, but there is for 2.0
          if (ctxInfo.version() >= GR_GL_VER(2,0)) {
              fMSFBOType = kStandard_MSFBOType;
          } else {
              fMSFBOType = kNone_MSFBOType;
          }
      }
  }
  
  void GrGLCaps::initBlendEqationSupport(const GrGLContextInfo& ctxInfo) {
      GrShaderCaps* shaderCaps = static_cast<GrShaderCaps*>(fShaderCaps.get());
  
      bool layoutQualifierSupport = false;
      if ((GR_IS_GR_GL(fStandard) && shaderCaps->generation() >= k140_GrGLSLGeneration)  ||
          (GR_IS_GR_GL_ES(fStandard) && shaderCaps->generation() >= k330_GrGLSLGeneration)) {
          layoutQualifierSupport = true;
      } else if (GR_IS_GR_WEBGL(fStandard)) {
          return;
      }
  
      if (ctxInfo.hasExtension("GL_NV_blend_equation_advanced_coherent")) {
          fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kAutomatic_AdvBlendEqInteraction;
      } else if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced_coherent") &&
                 layoutQualifierSupport) {
          fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kGeneralEnable_AdvBlendEqInteraction;
      } else if (ctxInfo.hasExtension("GL_NV_blend_equation_advanced")) {
          fBlendEquationSupport = kAdvanced_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kAutomatic_AdvBlendEqInteraction;
      } else if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced") && layoutQualifierSupport) {
          fBlendEquationSupport = kAdvanced_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kGeneralEnable_AdvBlendEqInteraction;
      }
  }
  
  
  void GrGLCaps::initStencilSupport(const GrGLContextInfo& ctxInfo) {
  
      // Build up list of legal stencil formats (though perhaps not supported on
      // the particular gpu/driver) from most preferred to least.
  
      // We push back stencil formats onto the fStencilFormats array in order of most preferred to
      // least preferred.
  
      if (GR_IS_GR_GL(ctxInfo.standard())) {
          bool supportsPackedDS =
              ctxInfo.version() >= GR_GL_VER(3,0) ||
              ctxInfo.hasExtension("GL_EXT_packed_depth_stencil") ||
              ctxInfo.hasExtension("GL_ARB_framebuffer_object");
  
          // S1 thru S16 formats are in GL 3.0+, EXT_FBO, and ARB_FBO since we
          // require FBO support we can expect these are legal formats and don't
          // check.
          fStencilFormats.push_back() = GrGLFormat::kSTENCIL_INDEX8;
          fStencilFormats.push_back() = GrGLFormat::kSTENCIL_INDEX16;
          if (supportsPackedDS) {
              fStencilFormats.push_back() = GrGLFormat::kDEPTH24_STENCIL8;
          }
      } else if (GR_IS_GR_GL_ES(ctxInfo.standard())) {
          // ES2 has STENCIL_INDEX8 without extensions but requires extensions
          // for other formats.
  
          fStencilFormats.push_back() = GrGLFormat::kSTENCIL_INDEX8;
          if (ctxInfo.version() >= GR_GL_VER(3,0) ||
              ctxInfo.hasExtension("GL_OES_packed_depth_stencil")) {
              fStencilFormats.push_back() = GrGLFormat::kDEPTH24_STENCIL8;
          }
      } else if (GR_IS_GR_WEBGL(ctxInfo.standard())) {
          fStencilFormats.push_back() = GrGLFormat::kSTENCIL_INDEX8;
          if (ctxInfo.version() >= GR_GL_VER(2,0)) {
              fStencilFormats.push_back() = GrGLFormat::kDEPTH24_STENCIL8;
          }
      }
  }
  
  #ifdef SK_ENABLE_DUMP_GPU
  static const char* multi_draw_type_name(GrGLCaps::MultiDrawType multiDrawType) {
      switch (multiDrawType) {
          case GrGLCaps::MultiDrawType::kNone : return "kNone";
          case GrGLCaps::MultiDrawType::kMultiDrawIndirect : return "kMultiDrawIndirect";
          case GrGLCaps::MultiDrawType::kANGLEOrWebGL : return "kMultiDrawIndirect";
      }
      SkUNREACHABLE;
  }
  
  void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const {
  
      // We are called by the base class, which has already called beginObject(). We choose to nest
      // all of our caps information in a named sub-object.
      writer->beginObject("GL caps");
  
      writer->beginArray("Stencil Formats");
  
      for (int i = 0; i < fStencilFormats.count(); ++i) {
          writer->beginObject(nullptr, false);
          writer->appendS32("stencil bits", GrGLFormatStencilBits(fStencilFormats[i]));
          writer->appendS32("total bytes", GrGLFormatBytesPerBlock(fStencilFormats[i]));
          writer->endObject();
      }
  
      writer->endArray();
  
      static const char* kMSFBOExtStr[] = {
          "None",
          "Standard",
          "Apple",
          "IMG MS To Texture",
          "EXT MS To Texture",
      };
      static_assert(0 == kNone_MSFBOType);
      static_assert(1 == kStandard_MSFBOType);
      static_assert(2 == kES_Apple_MSFBOType);
      static_assert(3 == kES_IMG_MsToTexture_MSFBOType);
      static_assert(4 == kES_EXT_MsToTexture_MSFBOType);
      static_assert(SK_ARRAY_COUNT(kMSFBOExtStr) == kLast_MSFBOType + 1);
  
      static const char* kInvalidateFBTypeStr[] = {
          "None",
          "Discard",
          "Invalidate",
      };
      static_assert(0 == kNone_InvalidateFBType);
      static_assert(1 == kDiscard_InvalidateFBType);
      static_assert(2 == kInvalidate_InvalidateFBType);
      static_assert(SK_ARRAY_COUNT(kInvalidateFBTypeStr) == kLast_InvalidateFBType + 1);
  
      static const char* kMapBufferTypeStr[] = {
          "None",
          "MapBuffer",
          "MapBufferRange",
          "Chromium",
      };
      static_assert(0 == kNone_MapBufferType);
      static_assert(1 == kMapBuffer_MapBufferType);
      static_assert(2 == kMapBufferRange_MapBufferType);
      static_assert(3 == kChromium_MapBufferType);
      static_assert(SK_ARRAY_COUNT(kMapBufferTypeStr) == kLast_MapBufferType + 1);
  
      writer->appendBool("Core Profile", fIsCoreProfile);
      writer->appendString("MSAA Type", kMSFBOExtStr[fMSFBOType]);
      writer->appendString("Invalidate FB Type", kInvalidateFBTypeStr[fInvalidateFBType]);
      writer->appendString("Map Buffer Type", kMapBufferTypeStr[fMapBufferType]);
      writer->appendString("Multi Draw Type", multi_draw_type_name(fMultiDrawType));
      writer->appendS32("Max FS Uniform Vectors", fMaxFragmentUniformVectors);
      writer->appendBool("Pack Flip Y support", fPackFlipYSupport);
  
      writer->appendBool("Texture Usage support", fTextureUsageSupport);
      writer->appendBool("GL_ARB_imaging support", fImagingSupport);
      writer->appendBool("Vertex array object support", fVertexArrayObjectSupport);
      writer->appendBool("Debug support", fDebugSupport);
      writer->appendBool("Base (vertex base) instance support", fBaseVertexBaseInstanceSupport);
      writer->appendBool("RGBA 8888 pixel ops are slow", fRGBA8888PixelsOpsAreSlow);
      writer->appendBool("Partial FBO read is slow", fPartialFBOReadIsSlow);
      writer->appendBool("Bind uniform location support", fBindUniformLocationSupport);
      writer->appendBool("Rectangle texture support", fRectangleTextureSupport);
      writer->appendBool("BGRA to RGBA readback conversions are slow",
                         fRGBAToBGRAReadbackConversionsAreSlow);
      writer->appendBool("Use buffer data null hint", fUseBufferDataNullHint);
      writer->appendBool("Clear texture support", fClearTextureSupport);
      writer->appendBool("Program binary support", fProgramBinarySupport);
      writer->appendBool("Program parameters support", fProgramParameterSupport);
      writer->appendBool("Sampler object support", fSamplerObjectSupport);
      writer->appendBool("Using sampler objects", fUseSamplerObjects);
      writer->appendBool("Texture swizzle support", fTextureSwizzleSupport);
      writer->appendBool("Tiled rendering support", fTiledRenderingSupport);
      writer->appendBool("FB fetch requires enable per sample", fFBFetchRequiresEnablePerSample);
      writer->appendBool("sRGB Write Control", fSRGBWriteControl);
  
      writer->appendBool("Intermediate texture for partial updates of unorm textures ever bound to FBOs",
                         fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO);
      writer->appendBool("Intermediate texture for all updates of textures bound to FBOs",
                         fUseDrawInsteadOfAllRenderTargetWrites);
      writer->appendBool("Max instances per draw without crashing (or zero)",
                         fMaxInstancesPerDrawWithoutCrashing);
  
      writer->beginArray("formats");
  
      for (int i = 0; i < kGrGLColorFormatCount; ++i) {
          writer->beginObject(nullptr, false);
          writer->appendHexU32("flags", fFormatTable[i].fFlags);
          writer->appendHexU32("f_type", (uint32_t)fFormatTable[i].fFormatType);
          writer->appendHexU32("c_internal", fFormatTable[i].fCompressedInternalFormat);
          writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImageOrStorage);
          writer->appendHexU32("i_for_renderbuffer", fFormatTable[i].fInternalFormatForRenderbuffer);
          writer->appendHexU32("default_ex_format", fFormatTable[i].fDefaultExternalFormat);
          writer->appendHexU32("default_ex_type", fFormatTable[i].fDefaultExternalType);
          writer->appendHexU32("default_color_type", (uint32_t)fFormatTable[i].fDefaultColorType);
  
          writer->beginArray("surface color types");
          for (int j = 0; j < fFormatTable[i].fColorTypeInfoCount; ++j) {
              const auto& ctInfo = fFormatTable[i].fColorTypeInfos[j];
              writer->beginObject(nullptr, false);
              writer->appendHexU32("colorType", (uint32_t)ctInfo.fColorType);
              writer->appendHexU32("flags", ctInfo.fFlags);
  
              writer->beginArray("data color types");
              for (int k = 0; k < ctInfo.fExternalIOFormatCount; ++k) {
                  const auto& ioInfo = ctInfo.fExternalIOFormats[k];
                  writer->beginObject(nullptr, false);
                  writer->appendHexU32("colorType", (uint32_t)ioInfo.fColorType);
                  writer->appendHexU32("ex_type", ioInfo.fExternalType);
                  writer->appendHexU32("ex_teximage", ioInfo.fExternalTexImageFormat);
                  writer->appendHexU32("ex_read", ioInfo.fExternalReadFormat);
                  writer->endObject();
              }
              writer->endArray();
              writer->endObject();
          }
          writer->endArray();
          writer->endObject();
      }
  
      writer->endArray();
      writer->endObject();
  }
  #else
  void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { }
  #endif
  
  void GrGLCaps::getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, GrGLenum* externalFormat,
                                                  GrGLenum* externalType) const {
      const auto& info = this->getFormatInfo(surfaceFormat);
      *externalType = info.fDefaultExternalType;
      *externalFormat = info.fDefaultExternalFormat;
  }
  
  void GrGLCaps::getTexSubImageDefaultFormatTypeAndColorType(GrGLFormat format,
                                                             GrGLenum* externalFormat,
                                                             GrGLenum* externalType,
                                                             GrColorType* colorType) const {
      const auto& info = this->getFormatInfo(format);
      *externalType = info.fDefaultExternalType;
      *externalFormat = info.fDefaultExternalFormat;
      *colorType = info.fDefaultColorType;
  }
  
  void GrGLCaps::getTexSubImageExternalFormatAndType(GrGLFormat surfaceFormat,
                                                     GrColorType surfaceColorType,
                                                     GrColorType memoryColorType,
                                                     GrGLenum* externalFormat,
                                                     GrGLenum* externalType) const {
      this->getExternalFormat(surfaceFormat, surfaceColorType, memoryColorType,
                              kTexImage_ExternalFormatUsage, externalFormat, externalType);
  }
  
  void GrGLCaps::getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
                                     GrColorType memoryColorType, GrGLenum* externalFormat,
                                     GrGLenum* externalType) const {
      this->getExternalFormat(surfaceFormat, surfaceColorType, memoryColorType,
                              kReadPixels_ExternalFormatUsage, externalFormat, externalType);
  }
  
  void GrGLCaps::getExternalFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
                                   GrColorType memoryColorType, ExternalFormatUsage usage,
                                   GrGLenum* externalFormat, GrGLenum* externalType) const {
      SkASSERT(externalFormat && externalType);
      *externalFormat = this->getFormatInfo(surfaceFormat).externalFormat(
              surfaceColorType, memoryColorType, usage);
      *externalType = this->getFormatInfo(surfaceFormat).externalType(
              surfaceColorType, memoryColorType);
  }
  
  void GrGLCaps::setStencilFormatIndexForFormat(GrGLFormat format, int index) {
      SkASSERT(!this->hasStencilFormatBeenDeterminedForFormat(format));
      this->getFormatInfo(format).fStencilFormatIndex =
              index < 0 ? FormatInfo::kUnsupported_StencilFormatIndex : index;
  }
  
  void GrGLCaps::setColorTypeFormat(GrColorType colorType, GrGLFormat format) {
      int idx = static_cast<int>(colorType);
      SkASSERT(fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown);
      fColorTypeToFormatTable[idx] = format;
  }
  
  void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli,
                                 const FormatWorkarounds& formatWorkarounds) {
      GrGLStandard standard = ctxInfo.standard();
      // standard can be unused (optimized away) if SK_ASSUME_GL_ES is set
      sk_ignore_unused_variable(standard);
      GrGLVersion version = ctxInfo.version();
  
      uint32_t nonMSAARenderFlags = FormatInfo::kFBOColorAttachment_Flag;
      uint32_t msaaRenderFlags = nonMSAARenderFlags;
      if (kNone_MSFBOType != fMSFBOType) {
          msaaRenderFlags |= FormatInfo::kFBOColorAttachmentWithMSAA_Flag;
      }
  
      bool texStorageSupported = false;
      if (GR_IS_GR_GL(standard)) {
          // The EXT version can apply to either GL or GLES.
          texStorageSupported = version >= GR_GL_VER(4,2) ||
                                ctxInfo.hasExtension("GL_ARB_texture_storage") ||
                                ctxInfo.hasExtension("GL_EXT_texture_storage");
      } else if (GR_IS_GR_GL_ES(standard)) {
          texStorageSupported = version >= GR_GL_VER(3,0) ||
                                ctxInfo.hasExtension("GL_EXT_texture_storage");
      } else if (GR_IS_GR_WEBGL(standard)) {
          texStorageSupported = version >= GR_GL_VER(2,0);
      }
      if (fDriverBugWorkarounds.disable_texture_storage) {
          texStorageSupported = false;
      }
  #ifdef SK_BUILD_FOR_ANDROID
      // crbug.com/945506. Telemetry reported a memory usage regression for Android Go Chrome/WebView
      // when using glTexStorage2D. This appears to affect OOP-R (so not just over command buffer).
      if (!formatWorkarounds.fDontDisableTexStorageOnAndroid) {
          texStorageSupported = false;
      }
  #endif
  
      // ES 2.0 requires that the internal/external formats match so we can't use sized internal
      // formats for glTexImage until ES 3.0. TODO: Support sized internal formats in WebGL2.
      bool texImageSupportsSizedInternalFormat =
              (GR_IS_GR_GL(standard) || (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3,0)));
  
      // for now we don't support floating point MSAA on ES
      uint32_t fpRenderFlags = (GR_IS_GR_GL(standard)) ? msaaRenderFlags : nonMSAARenderFlags;
  
      for (int i = 0; i < kGrColorTypeCnt; ++i) {
          fColorTypeToFormatTable[i] = GrGLFormat::kUnknown;
      }
  
      ///////////////////////////////////////////////////////////////////////////
  
      GrGLenum halfFloatType = GR_GL_HALF_FLOAT;
      if ((GR_IS_GR_GL_ES(standard) && version < GR_GL_VER(3, 0)) ||
          (GR_IS_GR_WEBGL(standard) && version < GR_GL_VER(2, 0))) {
          halfFloatType = GR_GL_HALF_FLOAT_OES;
      }
  
      // Format: RGBA8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
          info.fDefaultExternalFormat = GR_GL_RGBA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kRGBA_8888;
          info.fFlags = FormatInfo::kTexturable_Flag;
          if (GR_IS_GR_GL(standard)) {
              info.fFlags |= msaaRenderFlags;
          } else if (GR_IS_GR_GL_ES(standard)) {
              if (version >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_OES_rgb8_rgba8") ||
                  ctxInfo.hasExtension("GL_ARM_rgba8")) {
                  info.fFlags |= msaaRenderFlags;
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              info.fFlags |= msaaRenderFlags;
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA8;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
          }
  
          bool supportsBGRAColorType = GR_IS_GR_GL(standard) &&
                  (version >= GR_GL_VER(1, 2) || ctxInfo.hasExtension("GL_EXT_bgra"));
          info.fColorTypeInfoCount = supportsBGRAColorType ? 3 : 2;
          info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
          int ctIdx = 0;
          // Format: RGBA8, Surface: kRGBA_8888
          {
              auto& ctInfo = info.fColorTypeInfos[ctIdx++];
              ctInfo.fColorType = GrColorType::kRGBA_8888;
              ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
              this->setColorTypeFormat(GrColorType::kRGBA_8888, GrGLFormat::kRGBA8);
  
              // External IO ColorTypes:
              ctInfo.fExternalIOFormatCount = 2;
              ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                      ctInfo.fExternalIOFormatCount);
              int ioIdx = 0;
              // Format: RGBA8, Surface: kRGBA_8888, Data: kRGBA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGBA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
              }
              // Format: RGBA8, Surface: kRGBA_8888, Data: kBGRA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kBGRA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = 0;  // TODO: Enable this on non-ES GL
                  ioFormat.fExternalReadFormat =
                          formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
                  // Not guaranteed by ES/WebGL.
                  ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
              }
          }
  
          // Format: RGBA8, Surface: kBGRA_8888
          if (supportsBGRAColorType) {
              auto& ctInfo = info.fColorTypeInfos[ctIdx++];
              ctInfo.fColorType = GrColorType::kBGRA_8888;
              ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
              this->setColorTypeFormat(GrColorType::kBGRA_8888, GrGLFormat::kRGBA8);
  
              // External IO ColorTypes:
              ctInfo.fExternalIOFormatCount = 2;
              ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                      ctInfo.fExternalIOFormatCount);
              int ioIdx = 0;
              // Format: RGBA8, Surface: kBGRA_8888, Data: kBGRA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kBGRA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = GR_GL_BGRA;
                  ioFormat.fExternalReadFormat =
                          formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
                  // Not guaranteed by ES/WebGL.
                  ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
              }
  
              // Format: RGBA8, Surface: kBGRA_8888, Data: kRGBA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGBA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = 0;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
              }
          }
  
          // Format: RGBA8, Surface: kRGB_888x
          {
              auto& ctInfo = info.fColorTypeInfos[ctIdx++];
              ctInfo.fColorType = GrColorType::kRGB_888x;
              ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
              ctInfo.fReadSwizzle = GrSwizzle::RGB1();
  
              // External IO ColorTypes:
              ctInfo.fExternalIOFormatCount = 1;
              ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                      ctInfo.fExternalIOFormatCount);
              int ioIdx = 0;
              // Format: RGBA8, Surface: kRGB_888x, Data: kRGBA_888x
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGB_888x;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
              }
          }
      }
  
      // Format: R8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kR8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_R8;
          info.fDefaultExternalFormat = GR_GL_RED;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kR_8;
          bool r8Support = false;
          if (GR_IS_GR_GL(standard)) {
              r8Support = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg");
          } else if (GR_IS_GR_GL_ES(standard)) {
              r8Support = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_EXT_texture_rg");
          } else if (GR_IS_GR_WEBGL(standard)) {
              r8Support = ctxInfo.version() >= GR_GL_VER(2, 0);
          }
  
          if (r8Support) {
              info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_R8;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
          }
  
          if (r8Support) {
              info.fColorTypeInfoCount = 2;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: R8, Surface: kAlpha_8
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kAlpha_8;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  ctInfo.fReadSwizzle = GrSwizzle("000r");
                  ctInfo.fWriteSwizzle = GrSwizzle("a000");
                  this->setColorTypeFormat(GrColorType::kAlpha_8, GrGLFormat::kR8);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: R8, Surface: kAlpha_8, Data: kAlpha_8
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_8;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_RED;
                      ioFormat.fExternalReadFormat = GR_GL_RED;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: R8, Surface: kAlpha_8, Data: kAlpha_8xxx
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_8xxx;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
  
              // Format: R8, Surface: kGray_8
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kGray_8;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
                  ctInfo.fReadSwizzle = GrSwizzle("rrr1");
                  this->setColorTypeFormat(GrColorType::kGray_8, GrGLFormat::kR8);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: R8, Surface: kGray_8, Data: kGray_8
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kGray_8;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_RED;
                      ioFormat.fExternalReadFormat = GR_GL_RED;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: R8, Surface: kGray_8, Data: kGray_8xxx
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kGray_8xxx;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: ALPHA8
      {
          bool alpha8IsValidForGL = GR_IS_GR_GL(standard) &&
                  (!fIsCoreProfile || version <= GR_GL_VER(3, 0));
          bool alpha8IsValidForGLES = GR_IS_GR_GL_ES(standard);
          bool alpha8IsValidForWebGL = GR_IS_GR_WEBGL(standard);
  
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kALPHA8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          // GL_EXT_texture_storage adds GL_ALPHA8 for texture storage. However, ES3 has glTexStorage
          // but does not have GL_ALPHA8 (and requires a sized internal format for glTexStorage).
          // WebGL never has GL_ALPHA8.
          bool alpha8SizedEnumSupported =
                  alpha8IsValidForGL ||
                  (alpha8IsValidForGLES && ctxInfo.hasExtension("GL_EXT_texture_storage"));
          bool alpha8TexStorageSupported = alpha8SizedEnumSupported && texStorageSupported;
  
          bool alpha8IsRenderable = false;
          if (alpha8IsValidForGL) {
              // Core profile removes ALPHA8 support.
              // OpenGL 3.0+ (and GL_ARB_framebuffer_object) supports ALPHA8 as renderable.
              alpha8IsRenderable = ctxInfo.version() >= GR_GL_VER(3, 0) ||
                                   ctxInfo.hasExtension("GL_ARB_framebuffer_object");
          }
          info.fInternalFormatForRenderbuffer = GR_GL_ALPHA8;
          info.fDefaultExternalFormat = GR_GL_ALPHA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kAlpha_8;
          if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
              info.fFlags = FormatInfo::kTexturable_Flag;
          }
          if (alpha8IsRenderable && alpha8IsValidForGL) {
              // We will use ALPHA8 to create MSAA renderbuffers.
              SkASSERT(alpha8SizedEnumSupported);
              info.fFlags |= msaaRenderFlags;
          }
          if (alpha8TexStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
          } else {
              // Even if GL_ALPHA8 is added to ES by GL_EXT_texture_storage it doesn't become legal
              // for glTexImage2D.
              if (!GR_IS_GR_GL_ES(standard) && texImageSupportsSizedInternalFormat &&
                  alpha8SizedEnumSupported) {
                  info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
              } else {
                  info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA;
              }
          }
  
          if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: ALPHA8, Surface: kAlpha_8
              {
                  if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
                      auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                      ctInfo.fColorType = GrColorType::kAlpha_8;
                      ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag |
                                      ColorTypeInfo::kRenderable_Flag;
                      int idx = static_cast<int>(GrColorType::kAlpha_8);
                      if (fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown) {
                          this->setColorTypeFormat(GrColorType::kAlpha_8, GrGLFormat::kALPHA8);
                      }
  
                      // External IO ColorTypes:
                      ctInfo.fExternalIOFormatCount = 2;
                      ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                              ctInfo.fExternalIOFormatCount);
                      int ioIdx = 0;
                      // Format: ALPHA8, Surface: kAlpha_8, Data: kAlpha_8
                      {
                          auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                          ioFormat.fColorType = GrColorType::kAlpha_8;
                          ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                          ioFormat.fExternalTexImageFormat = GR_GL_ALPHA;
                          ioFormat.fExternalReadFormat = GR_GL_ALPHA;
                          // Not guaranteed by ES/WebGL.
                          ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                      }
  
                      // Format: ALPHA8, Surface: kAlpha_8, Data: kRGBA_8888
                      {
                          auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                          ioFormat.fColorType = GrColorType::kRGBA_8888;
                          ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                          ioFormat.fExternalTexImageFormat = 0;
                          ioFormat.fExternalReadFormat = GR_GL_RGBA;
                      }
                  }
              }
          }
      }
  
      // Format: LUMINANCE8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8;
          info.fDefaultExternalFormat = GR_GL_LUMINANCE;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kGray_8;
          bool lum8Supported = false;
          bool lum8SizedFormatSupported = false;
          if (GR_IS_GR_GL(standard) && !fIsCoreProfile) {
              lum8Supported = true;
              lum8SizedFormatSupported = true;
          } else if (GR_IS_GR_GL_ES(standard)) {
              lum8Supported = true;
              // Even on ES3 this extension is required to define LUMINANCE8.
              lum8SizedFormatSupported = ctxInfo.hasExtension("GL_EXT_texture_storage");
          } else if (GR_IS_GR_WEBGL(standard)) {
              lum8Supported = true;
          }
          if (lum8Supported) {
              info.fFlags = FormatInfo::kTexturable_Flag;
          }
          if (texStorageSupported && lum8SizedFormatSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8;
          } else if (texImageSupportsSizedInternalFormat && lum8SizedFormatSupported) {
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8;
          } else {
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE;
          }
          // We are not enabling attaching to an FBO for LUMINANCE8 mostly because of confusion in the
          // spec. For GLES it does not seem to ever support LUMINANCE8 being color-renderable. For GL
          // versions less than 3.0 it is provided by GL_ARB_framebuffer_object. However, the original
          // version of that extension did not add LUMINANCE8, but was added in a later revsion. So
          // even the presence of that extension does not guarantee support. GL 3.0 and higher (core
          // or compatibility) do not list LUMINANCE8 as color-renderable (which is strange since the
          // GL_ARB_framebuffer_object extension was meant to bring 3.0 functionality to lower
          // versions).
  
          if (lum8Supported) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: LUMINANCE8, Surface: kGray_8
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kGray_8;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
                  int idx = static_cast<int>(GrColorType::kGray_8);
                  if (fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown) {
                      this->setColorTypeFormat(GrColorType::kGray_8, GrGLFormat::kLUMINANCE8);
                  }
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: LUMINANCE8, Surface: kGray_8, Data: kGray_8
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kGray_8;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_LUMINANCE;
                      ioFormat.fExternalReadFormat = 0;
                  }
  
                  // Format: LUMINANCE8, Surface: kGray_8, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: LUMINANCE8_ALPHA8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8_ALPHA8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8_ALPHA8;
          info.fDefaultExternalFormat = GR_GL_LUMINANCE_ALPHA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kGrayAlpha_88;
          bool la8Supported = false;
          bool la8SizedFormatSupported = false;
          if (GR_IS_GR_GL(standard) && !fIsCoreProfile) {
              la8Supported = true;
              la8SizedFormatSupported = true;
          } else if (GR_IS_GR_GL_ES(standard)) {
              la8Supported = true;
              // Even on ES3 this extension is required to define LUMINANCE8_ALPHA8.
              la8SizedFormatSupported = ctxInfo.hasExtension("GL_EXT_texture_storage");
          } else if (GR_IS_GR_WEBGL(standard)) {
              la8Supported = true;
          }
          if (la8Supported) {
              info.fFlags = FormatInfo::kTexturable_Flag;
          }
          if (texStorageSupported && la8SizedFormatSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8_ALPHA8;
          } else if (texImageSupportsSizedInternalFormat && la8SizedFormatSupported) {
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8_ALPHA8;
          } else {
              info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE_ALPHA;
          }
          // See note in LUMINANCE8 section about not attaching to framebuffers.
  
          if (la8Supported) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: LUMINANCE8_ALPHA8, Surface: kGrayAlpha_88
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kGrayAlpha_88;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
                  int idx = static_cast<int>(GrColorType::kGrayAlpha_88);
                  if (fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown) {
                      this->setColorTypeFormat(GrColorType::kGrayAlpha_88,
                                               GrGLFormat::kLUMINANCE8_ALPHA8);
                  }
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: LUMINANCE8, Surface: kGrayAlpha_88, Data: kGrayAlpha_88
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kGrayAlpha_88;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_LUMINANCE_ALPHA;
                      ioFormat.fExternalReadFormat = 0;
                  }
  
                  // Format: LUMINANCE8, Surface: kGrayAlpha_88, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
      // Format: BGRA8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kBGRA8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
  
          // We currently only use the renderbuffer format when allocating msaa renderbuffers, so we
          // are making decisions here based on that use case. The GL_EXT_texture_format_BGRA8888
          // extension adds BGRA color renderbuffer support for ES 2.0, but this does not guarantee
          // support for MSAA renderbuffers. Additionally, the renderable support was added in a later
          // revision of the extension. So it is possible for older drivers to support the extension
          // but only an early revision of it without renderable support. We have no way of
          // distinguishing between the two. The GL_APPLE_texture_format_BGRA8888 does not add support
          // for BGRA color renderbuffers at all. Ideally, for both cases we would use RGBA8 for our
          // format for the MSAA buffer. In the GL_EXT_texture_format_BGRA8888 case we can still
          // make the resolve BGRA and which will work for glBlitFramebuffer for resolving which just
          // requires the src and dst be bindable to FBOs. However, we can't do this in the current
          // world since some devices (e.g. chromium & angle) require the formats in glBlitFramebuffer
          // to match. We don't have a way to really check this during resolve since we only actually
          // have GrBackendFormat that is shared by the GrGLRenderTarget. We always set the
          // renderbuffer format to RGBA8 but disable MSAA unless we have the APPLE extension.
          // Once we break those up into different surface we can revisit doing this change.
          info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
  
          info.fDefaultExternalFormat = GR_GL_BGRA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kBGRA_8888;
  
          GrGLenum bgraTexImageFormat;
          // If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image
          // as a base format. Which base format depends on which extension is used.
          if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
              // GL_APPLE_texture_format_BGRA8888:
              //     ES 2.0: the extension makes BGRA an external format but not an internal format.
              //     ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format
              //             for glTexImage (just for glTexStorage).
              bgraTexImageFormat = GR_GL_RGBA;
          } else {
              // GL_EXT_texture_format_BGRA8888:
              //      This extension adds GL_BGRA as an unsized internal format. However, it is
              //      written against ES 2.0 and therefore doesn't define a GL_BGRA8 as ES 2.0 doesn't
              //      have sized internal formats. See later where we check for tex storage BGRA8
              //      support.
              bgraTexImageFormat = GR_GL_BGRA;
          }
  
          // TexStorage requires using a sized internal format and BGRA8 is only supported if we have
          // the GL_APPLE_texture_format_BGRA8888 extension or if we have GL_EXT_texture_storage and
          // GL_EXT_texture_format_BGRA8888.
          bool supportsBGRATexStorage = false;
  
          if (GR_IS_GR_GL_ES(standard)) {
              if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) {
                  info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags;
                  // GL_EXT_texture storage has defined interactions with
                  // GL_EXT_texture_format_BGRA8888. However, ES3 supports glTexStorage but
                  // without GL_EXT_texture_storage it does not allow the BGRA8 sized internal format.
                  if (ctxInfo.hasExtension("GL_EXT_texture_storage") &&
                      !formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) {
                      supportsBGRATexStorage = true;
                  }
              } else if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
                  // This APPLE extension introduces complexity on ES2. It leaves the internal format
                  // as RGBA, but allows BGRA as the external format. From testing, it appears that
                  // the driver remembers the external format when the texture is created (with
                  // TexImage). If you then try to upload data in the other swizzle (with
                  // TexSubImage), it fails. We could work around this, but it adds even more state
                  // tracking to code that is already too tricky. Instead, we opt not to support BGRA
                  // on ES2 with this extension. This also side-steps some ambiguous interactions with
                  // the texture storage extension.
                  if (version >= GR_GL_VER(3,0)) {
                      // The APPLE extension doesn't explicitly make this renderable, but
                      // internally it appears to use RGBA8, which we'll patch up below.
                      info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
                      supportsBGRATexStorage = true;
                  }
              }
          }
          if (texStorageSupported && supportsBGRATexStorage) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_BGRA8;
          } else {
              info.fInternalFormatForTexImageOrStorage = bgraTexImageFormat;
          }
  
          if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: BGRA8, Surface: kBGRA_8888
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kBGRA_8888;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kBGRA_8888, GrGLFormat::kBGRA8);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: BGRA8, Surface: kBGRA_8888, Data: kBGRA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kBGRA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_BGRA;
                      ioFormat.fExternalReadFormat = 0;
                      ioFormat.fExternalReadFormat =
                              formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: BGRA8, Surface: kBGRA_8888, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGB565
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB565);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RGB565;
          info.fDefaultExternalFormat = GR_GL_RGB;
          info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
          info.fDefaultColorType = GrColorType::kBGR_565;
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
                  info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          } else if (GR_IS_GR_WEBGL(standard)) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          }
          // 565 is not a sized internal format on desktop GL. So on desktop with
          // 565 we always use an unsized internal format to let the system pick
          // the best sized format to convert the 565 data to. Since TexStorage
          // only allows sized internal formats we disallow it.
          //
          // TODO: As of 4.2, regular GL supports 565. This logic is due for an
          // update.
          if (texStorageSupported && GR_IS_GR_GL_ES(standard)) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGB565;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
          }
  
          if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: RGB565, Surface: kBGR_565
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kBGR_565;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kBGR_565, GrGLFormat::kRGB565);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RGB565, Surface: kBGR_565, Data: kBGR_565
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kBGR_565;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
                      ioFormat.fExternalTexImageFormat = GR_GL_RGB;
                      ioFormat.fExternalReadFormat = GR_GL_RGB;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: RGB565, Surface: kBGR_565, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGBA16F
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16F);
          info.fFormatType = FormatType::kFloat;
          info.fInternalFormatForRenderbuffer = GR_GL_RGBA16F;
          info.fDefaultExternalFormat = GR_GL_RGBA;
          info.fDefaultExternalType = halfFloatType;
          info.fDefaultColorType = GrColorType::kRGBA_F16;
          bool rgba16FTextureSupport = false;
          bool rgba16FRenderTargetSupport = false;
  
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(3, 0)) {
                  rgba16FTextureSupport = true;
                  rgba16FRenderTargetSupport = true;
              } else if (ctxInfo.hasExtension("GL_ARB_texture_float")) {
                  rgba16FTextureSupport = true;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              if (version >= GR_GL_VER(3, 0)) {
                  rgba16FTextureSupport = true;
                  rgba16FRenderTargetSupport =
                          version >= GR_GL_VER(3, 2) ||
                          ctxInfo.hasExtension("GL_EXT_color_buffer_half_float") ||
                          ctxInfo.hasExtension("GL_EXT_color_buffer_float");
              } else if (ctxInfo.hasExtension("GL_OES_texture_half_float") &&
                         ctxInfo.hasExtension("GL_OES_texture_half_float_linear")) {
                  rgba16FTextureSupport = true;
                  rgba16FRenderTargetSupport = ctxInfo.hasExtension("GL_EXT_color_buffer_half_float");
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              if (version >= GR_GL_VER(2, 0)) {
                  rgba16FTextureSupport = true;
                  rgba16FRenderTargetSupport =
                          ctxInfo.hasExtension("GL_EXT_color_buffer_half_float") ||
                          ctxInfo.hasExtension("EXT_color_buffer_half_float") ||
                          ctxInfo.hasExtension("GL_EXT_color_buffer_float") ||
                          ctxInfo.hasExtension("EXT_color_buffer_float");
              } else if ((ctxInfo.hasExtension("GL_OES_texture_half_float") ||
                          ctxInfo.hasExtension("OES_texture_half_float")) &&
                         (ctxInfo.hasExtension("GL_OES_texture_half_float_linear") ||
                          ctxInfo.hasExtension("OES_texture_half_float_linear"))) {
                  rgba16FTextureSupport = true;
                  // We don't check for EXT_color_buffer_float as it's only defined for WebGL 2.
                  rgba16FRenderTargetSupport =
                          ctxInfo.hasExtension("GL_EXT_color_buffer_half_float") ||
                          ctxInfo.hasExtension("EXT_color_buffer_half_float");
              }
          }
  
          if (rgba16FTextureSupport) {
              info.fFlags = FormatInfo::kTexturable_Flag;
              if (rgba16FRenderTargetSupport) {
                  info.fFlags |= fpRenderFlags;
              }
          }
          if (texStorageSupported && !formatWorkarounds.fDisableRGBA16FTexStorageForCrBug1008003) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA16F;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
          }
  
          if (rgba16FTextureSupport) {
              uint32_t flags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
  
              info.fColorTypeInfoCount = 2;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: RGBA16F, Surface: kRGBA_F16
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRGBA_F16;
                  ctInfo.fFlags = flags;
                  this->setColorTypeFormat(GrColorType::kRGBA_F16, GrGLFormat::kRGBA16F);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RGBA16F, Surface: kRGBA_F16, Data: kRGBA_F16
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F16;
                      ioFormat.fExternalType = halfFloatType;
                      ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: RGBA16F, Surface: kRGBA_F16, Data: kRGBA_F32
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F32;
                      ioFormat.fExternalType = GR_GL_FLOAT;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
  
              // Format: RGBA16F, Surface: kRGBA_F16_Clamped
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRGBA_F16_Clamped;
                  ctInfo.fFlags = flags;
                  this->setColorTypeFormat(GrColorType::kRGBA_F16_Clamped, GrGLFormat::kRGBA16F);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RGBA16F, Surface: kRGBA_F16_Clamped, Data: kRGBA_F16_Clamped
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F16_Clamped;
                      ioFormat.fExternalType = halfFloatType;
                      ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: RGBA16F, Surface: kRGBA_F16_Clamped, Data: kRGBA_F32
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F32;
                      ioFormat.fExternalType = GR_GL_FLOAT;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: R16F
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16F);
          info.fFormatType = FormatType::kFloat;
          info.fInternalFormatForRenderbuffer = GR_GL_R16F;
          info.fDefaultExternalFormat = GR_GL_RED;
          info.fDefaultExternalType = halfFloatType;
          info.fDefaultColorType = GrColorType::kR_F16;
          bool r16FTextureSupport = false;
          bool r16FRenderTargetSupport = false;
  
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg")) {
                  r16FTextureSupport = true;
                  r16FRenderTargetSupport = true;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              // It seems possible that a combination of GL_EXT_texture_rg and
              // GL_EXT_color_buffer_half_float might add this format to ES 2.0 but it is not entirely
              // clear. The latter mentions interaction but that may only be for renderbuffers as
              // neither adds the texture format explicitly.
              // GL_OES_texture_format_half_float makes no reference to RED formats.
              if (version >= GR_GL_VER(3, 0)) {
                  r16FTextureSupport = true;
                  r16FRenderTargetSupport = version >= GR_GL_VER(3, 2) ||
                                            ctxInfo.hasExtension("GL_EXT_color_buffer_float") ||
                                            ctxInfo.hasExtension("GL_EXT_color_buffer_half_float");
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              if (version >= GR_GL_VER(2, 0)) {
                  r16FTextureSupport = true;
                  r16FRenderTargetSupport = ctxInfo.hasExtension("GL_EXT_color_buffer_float") ||
                                            ctxInfo.hasExtension("EXT_color_buffer_float");
              }
          }
  
          if (r16FTextureSupport) {
              info.fFlags = FormatInfo::kTexturable_Flag;
              if (r16FRenderTargetSupport) {
                  info.fFlags |= fpRenderFlags;
              }
          }
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_R16F;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
          }
  
          if (r16FTextureSupport) {
              // Format: R16F, Surface: kAlpha_F16
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kAlpha_F16;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  ctInfo.fReadSwizzle = GrSwizzle("000r");
                  ctInfo.fWriteSwizzle = GrSwizzle("a000");
                  this->setColorTypeFormat(GrColorType::kAlpha_F16, GrGLFormat::kR16F);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: R16F, Surface: kAlpha_F16, Data: kAlpha_F16
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_F16;
                      ioFormat.fExternalType = halfFloatType;
                      ioFormat.fExternalTexImageFormat = GR_GL_RED;
                      ioFormat.fExternalReadFormat = GR_GL_RED;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: R16F, Surface: kAlpha_F16, Data: kAlpha_F32xxx
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_F32xxx;
                      ioFormat.fExternalType = GR_GL_FLOAT;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: LUMINANCE16F
      {
          // NOTE: We disallow lum16f on ES devices if linear filtering modes are not
          // supported. This is for simplicity, but a more granular approach is possible.
          bool lum16FSupported = false;
          bool lum16FSizedFormatSupported = false;
          if (GR_IS_GR_GL(standard)) {
              if (!fIsCoreProfile && ctxInfo.hasExtension("GL_ARB_texture_float")) {
                  lum16FSupported = true;
                  lum16FSizedFormatSupported = true;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              if (ctxInfo.hasExtension("GL_OES_texture_half_float_linear") &&
                  ctxInfo.hasExtension("GL_OES_texture_half_float")) {
                  lum16FSupported = true;
                  // Even on ES3 this extension is required to define LUMINANCE16F.
                  lum16FSizedFormatSupported = ctxInfo.hasExtension("GL_EXT_texture_storage");
              }
          } // No WebGL support
  
          if (formatWorkarounds.fDisableLuminance16F) {
              lum16FSupported = false;
          }
  
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE16F);
          info.fFormatType = FormatType::kFloat;
          info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE16F;
          info.fDefaultExternalFormat = GR_GL_LUMINANCE;
          info.fDefaultExternalType = halfFloatType;
          info.fDefaultColorType = GrColorType::kGray_F16;
  
          if (lum16FSupported) {
              info.fFlags = FormatInfo::kTexturable_Flag;
  
              if (texStorageSupported && lum16FSizedFormatSupported) {
                  info.fFlags |= FormatInfo::kUseTexStorage_Flag;
                  info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE16F;
              } else if (texImageSupportsSizedInternalFormat && lum16FSizedFormatSupported) {
                  info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE16F;
              } else {
                  info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE;
              }
  
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: LUMINANCE16F, Surface: kAlpha_F16
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kAlpha_F16;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
                  ctInfo.fReadSwizzle = GrSwizzle("000r");
                  ctInfo.fWriteSwizzle = GrSwizzle("aaa0");
  
                  int idx = static_cast<int>(GrColorType::kAlpha_F16);
                  if (fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown) {
                      this->setColorTypeFormat(GrColorType::kAlpha_F16, GrGLFormat::kLUMINANCE16F);
                  }
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: LUMINANCE16F, Surface: kAlpha_F16, Data: kAlpha_F16
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_F16;
                      ioFormat.fExternalType = halfFloatType;
                      ioFormat.fExternalTexImageFormat = GR_GL_LUMINANCE;
                      ioFormat.fExternalReadFormat = 0;
                  }
  
                  // Format: LUMINANCE16F, Surface: kAlpha_F16, Data: kRGBA_F32
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F32;
                      ioFormat.fExternalType = GR_GL_FLOAT;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGB8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RGB8;
          info.fDefaultExternalFormat = GR_GL_RGB;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kRGB_888;
          info.fFlags = FormatInfo::kTexturable_Flag;
          if (GR_IS_GR_GL(standard)) {
              // Even in OpenGL 4.6 GL_RGB8 is required to be color renderable but not required to be
              // a supported render buffer format. Since we usually use render buffers for MSAA on
              // non-ES GL we don't support MSAA for GL_RGB8. On 4.2+ we could check using
              // glGetInternalFormativ(GL_RENDERBUFFER, GL_RGB8, GL_INTERNALFORMAT_SUPPORTED, ...) if
              // this becomes an issue.
              // This also would probably work in mixed-samples mode where there is no MSAA color
              // buffer but we don't support that just for simplicity's sake.
              info.fFlags |= nonMSAARenderFlags;
          } else if (GR_IS_GR_GL_ES(standard)) {
              // 3.0 and the extension support this as a render buffer format.
              if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_OES_rgb8_rgba8")) {
                  info.fFlags |= msaaRenderFlags;
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              // WebGL seems to support RBG8
              info.fFlags |= msaaRenderFlags;
          }
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGB8;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
          }
  
          info.fColorTypeInfoCount = 1;
          info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
          int ctIdx = 0;
          // Format: RGB8, Surface: kRGB_888x
          {
              auto& ctInfo = info.fColorTypeInfos[ctIdx++];
              ctInfo.fColorType = GrColorType::kRGB_888x;
              ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
              this->setColorTypeFormat(GrColorType::kRGB_888x, GrGLFormat::kRGB8);
  
              // External IO ColorTypes:
              ctInfo.fExternalIOFormatCount = 2;
              ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                      ctInfo.fExternalIOFormatCount);
              int ioIdx = 0;
              // Format: RGB8, Surface: kRGB_888x, Data: kRGB_888x
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGB_888x;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  // This is technically the wrong format to use for this color type since the color
                  // type is 4 bytes but the format is 3. However, we don't currently upload data of
                  // this type so the format is only used when creating an empty texture. If we want
                  // to support uploading data we should add in RGB_888 GrColorType. Additionally, on
                  // the FormatInfo we should have a default format to use when we want to create an
                  // empty texture.
                  ioFormat.fExternalTexImageFormat = GR_GL_RGB;
                  ioFormat.fExternalReadFormat = 0;
              }
  
              // Format: RGB8, Surface: kRGB_888x, Data: kRGBA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGBA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = 0;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
              }
          }
      }
  
      // Format: RG8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RG8;
          info.fDefaultExternalFormat = GR_GL_RG;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kRG_88;
          bool rg8Support = false;
          if (GR_IS_GR_GL(standard)) {
              rg8Support = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg");
          } else if (GR_IS_GR_GL_ES(standard)) {
              rg8Support = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_EXT_texture_rg");
          } else if (GR_IS_GR_WEBGL(standard)) {
              rg8Support = version >= GR_GL_VER(2, 0);
          }
          if (rg8Support) {
              info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
              if (texStorageSupported) {
                  info.fFlags |= FormatInfo::kUseTexStorage_Flag;
                  info.fInternalFormatForTexImageOrStorage = GR_GL_RG8;
              }
          }
          if (!(info.fFlags & FormatInfo::kUseTexStorage_Flag)) {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RG8 : GR_GL_RG;
          }
          if (rg8Support) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: RG8, Surface: kRG_88
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRG_88;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRG_88, GrGLFormat::kRG8);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RG8, Surface: kRG_88, Data: kRG_88
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRG_88;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = GR_GL_RG;
                      ioFormat.fExternalReadFormat = 0;
                      if (GR_IS_GR_GL(standard) && !formatWorkarounds.fDisallowDirectRG8ReadPixels) {
                          ioFormat.fExternalReadFormat = GR_GL_RG;
                      }
                  }
  
                  // Format: RG8, Surface: kRG_88, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGB10_A2
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB10_A2);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RGB10_A2;
          info.fDefaultExternalFormat = GR_GL_RGBA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
          info.fDefaultColorType = GrColorType::kRGBA_1010102;
          if (GR_IS_GR_GL(standard) ||
             (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          } else if (GR_IS_GR_GL_ES(standard) &&
                     ctxInfo.hasExtension("GL_EXT_texture_type_2_10_10_10_REV")) {
              info.fFlags = FormatInfo::kTexturable_Flag;
          } // No WebGL support
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGB10_A2;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
          }
  
          if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
              bool supportsBGRAColorType = GR_IS_GR_GL(standard) &&
                      (version >= GR_GL_VER(1, 2) || ctxInfo.hasExtension("GL_EXT_bgra"));
  
              info.fColorTypeInfoCount = supportsBGRAColorType ? 2 : 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: RGB10_A2, Surface: kRGBA_1010102
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRGBA_1010102;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRGBA_1010102, GrGLFormat::kRGB10_A2);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RGB10_A2, Surface: kRGBA_1010102, Data: kRGBA_1010102
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_1010102;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
                      ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: RGB10_A2, Surface: kRGBA_1010102, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
              //------------------------------------------------------------------
              // Format: RGB10_A2, Surface: kBGRA_1010102
              if (supportsBGRAColorType) {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kBGRA_1010102;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kBGRA_1010102, GrGLFormat::kRGB10_A2);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: RGB10_A2, Surface: kBGRA_1010102, Data: kBGRA_1010102
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kBGRA_1010102;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
                      ioFormat.fExternalTexImageFormat = GR_GL_BGRA;
                      ioFormat.fExternalReadFormat =
                              formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: RGB10_A2, Surface: kBGRA_1010102, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGBA4
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA4);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_RGBA4;
          info.fDefaultExternalFormat = GR_GL_RGBA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
          info.fDefaultColorType = GrColorType::kABGR_4444;
          info.fFlags = FormatInfo::kTexturable_Flag;
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(4, 2)) {
                  info.fFlags |= msaaRenderFlags;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              info.fFlags |= msaaRenderFlags;
          } else if (GR_IS_GR_WEBGL(standard)) {
              info.fFlags |= msaaRenderFlags;
          }
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA4;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
          }
  
          info.fColorTypeInfoCount = 1;
          info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
          int ctIdx = 0;
          // Format: RGBA4, Surface: kABGR_4444
          {
              auto& ctInfo = info.fColorTypeInfos[ctIdx++];
              ctInfo.fColorType = GrColorType::kABGR_4444;
              ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
              this->setColorTypeFormat(GrColorType::kABGR_4444, GrGLFormat::kRGBA4);
  
              // External IO ColorTypes:
              ctInfo.fExternalIOFormatCount = 2;
              ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                      ctInfo.fExternalIOFormatCount);
              int ioIdx = 0;
              // Format: RGBA4, Surface: kABGR_4444, Data: kABGR_4444
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kABGR_4444;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
                  ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  // Not guaranteed by ES/WebGL.
                  ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
              }
  
              // Format: RGBA4, Surface: kABGR_4444, Data: kRGBA_8888
              {
                  auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                  ioFormat.fColorType = GrColorType::kRGBA_8888;
                  ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                  ioFormat.fExternalTexImageFormat = 0;
                  ioFormat.fExternalReadFormat = GR_GL_RGBA;
              }
          }
      }
  
      // Format: SRGB8_ALPHA8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kSRGB8_ALPHA8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_SRGB8_ALPHA8;
          info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
          info.fDefaultColorType = GrColorType::kRGBA_8888_SRGB;
  
          // We may modify the default external format below.
          info.fDefaultExternalFormat = GR_GL_RGBA;
          bool srgb8Alpha8TexStorageSupported = texStorageSupported;
          bool srgb8Alpha8TextureSupport = false;
          bool srgb8Alpha8RenderTargetSupport = false;
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(3, 0)) {
                  srgb8Alpha8TextureSupport = true;
                  srgb8Alpha8RenderTargetSupport = true;
              } else if (ctxInfo.hasExtension("GL_EXT_texture_sRGB")) {
                  srgb8Alpha8TextureSupport = true;
                  if (ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") ||
                      ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB")) {
                      srgb8Alpha8RenderTargetSupport = true;
                  }
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_EXT_sRGB")) {
                  srgb8Alpha8TextureSupport = true;
                  srgb8Alpha8RenderTargetSupport = true;
              }
              if (version < GR_GL_VER(3, 0)) {
                  // ES 2.0 requires that the external format matches the internal format.
                  info.fDefaultExternalFormat = GR_GL_SRGB_ALPHA;
                  // There is no defined interaction between GL_EXT_sRGB and GL_EXT_texture_storage.
                  srgb8Alpha8TexStorageSupported = false;
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              // sRGB extension should be on most WebGL 1.0 contexts, although sometimes under 2
              // names.
              if (version >= GR_GL_VER(2, 0) || ctxInfo.hasExtension("GL_EXT_sRGB") ||
                  ctxInfo.hasExtension("EXT_sRGB")) {
                  srgb8Alpha8TextureSupport = true;
                  srgb8Alpha8RenderTargetSupport = true;
              }
              if (version < GR_GL_VER(2, 0)) {
                  // WebGL 1.0 requires that the external format matches the internal format.
                  info.fDefaultExternalFormat = GR_GL_SRGB_ALPHA;
                  // There is no extension to WebGL 1 that adds glTexStorage.
                  SkASSERT(!srgb8Alpha8TexStorageSupported);
              }
          }
  
          if (srgb8Alpha8TextureSupport) {
              info.fFlags = FormatInfo::kTexturable_Flag;
              if (srgb8Alpha8RenderTargetSupport) {
                  info.fFlags |= formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD
                                         ? nonMSAARenderFlags
                                         : msaaRenderFlags;
              }
          }
          if (srgb8Alpha8TexStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_SRGB8_ALPHA8;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
          }
  
          if (srgb8Alpha8TextureSupport) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: SRGB8_ALPHA8, Surface: kRGBA_8888_SRGB
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRGBA_8888_SRGB;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRGBA_8888_SRGB, GrGLFormat::kSRGB8_ALPHA8);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 1;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
  
                  // Format: SRGB8_ALPHA8, Surface: kRGBA_8888_SRGB, Data: kRGBA_8888_SRGB
                  {
                      // GL does not do srgb<->rgb conversions when transferring between cpu and gpu.
                      // Thus, the external format is GL_RGBA. See below for note about ES2.0 and
                      // glTex[Sub]Image.
                      GrGLenum texImageExternalFormat = GR_GL_RGBA;
  
                      // OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the
                      // <format> param to Tex(Sub)Image. ES 2.0 requires the <internalFormat> and
                      // <format> params to match. Thus, on ES 2.0 we will use GL_SRGB_ALPHA as the
                      // <format> param. On OpenGL and ES 3.0+ GL_SRGB_ALPHA does not work for the
                      // <format> param to glTexImage.
                      if (GR_IS_GR_GL_ES(standard) && version == GR_GL_VER(2,0)) {
                          texImageExternalFormat = GR_GL_SRGB_ALPHA;
                      }
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888_SRGB;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = texImageExternalFormat;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: COMPRESSED_RGB8_BC1
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_BC1);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
          if (GR_IS_GR_GL(standard) || GR_IS_GR_GL_ES(standard)) {
              if (ctxInfo.hasExtension("GL_EXT_texture_compression_s3tc")) {
                  info.fFlags = FormatInfo::kTexturable_Flag;
              }
          } // No WebGL support
  
          // There are no support GrColorTypes for this format
      }
  
      // Format: COMPRESSED_RGBA8_BC1
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGBA8_BC1);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
          if (GR_IS_GR_GL(standard) || GR_IS_GR_GL_ES(standard)) {
              if (ctxInfo.hasExtension("GL_EXT_texture_compression_s3tc")) {
                  info.fFlags = FormatInfo::kTexturable_Flag;
              }
          } // No WebGL support
  
            // There are no support GrColorTypes for this format
      }
  
      // Format: COMPRESSED_RGB8_ETC2
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB8_ETC2;
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) {
                  info.fFlags = FormatInfo::kTexturable_Flag;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              if (version >= GR_GL_VER(3, 0) ||
                  ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture")) {
                  info.fFlags = FormatInfo::kTexturable_Flag;
              }
          } // No WebGL support
  
          // There are no support GrColorTypes for this format
      }
  
      // Format: COMPRESSED_ETC1_RGB8
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_ETC1_RGB8;
          if (GR_IS_GR_GL_ES(standard)) {
              if (ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
                  info.fFlags = FormatInfo::kTexturable_Flag;
              }
          } // No GL or WebGL support
  
          // There are no support GrColorTypes for this format
      }
  
      // Format: R16
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForRenderbuffer = GR_GL_R16;
          info.fDefaultExternalFormat = GR_GL_RED;
          info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
          info.fDefaultColorType = GrColorType::kR_16;
          bool r16Supported = false;
          if (GR_IS_GR_GL(standard)) {
              r16Supported = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg");
          } else if (GR_IS_GR_GL_ES(standard)) {
              r16Supported = ctxInfo.hasExtension("GL_EXT_texture_norm16");
          }  // No WebGL support
  
          if (r16Supported) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_R16;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_R16 : GR_GL_RED;
          }
  
          if (r16Supported) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: R16, Surface: kAlpha_16
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kAlpha_16;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  ctInfo.fReadSwizzle = GrSwizzle("000r");
                  ctInfo.fWriteSwizzle = GrSwizzle("a000");
                  this->setColorTypeFormat(GrColorType::kAlpha_16, GrGLFormat::kR16);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: R16, Surface: kAlpha_16, Data: kAlpha_16
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_16;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
                      ioFormat.fExternalTexImageFormat = GR_GL_RED;
                      ioFormat.fExternalReadFormat = GR_GL_RED;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: R16, Surface: kAlpha_16, Data: kAlpha_8xxx
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kAlpha_8xxx;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RG16
      {
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
          info.fInternalFormatForTexImageOrStorage =
                  texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG;
          info.fInternalFormatForRenderbuffer = GR_GL_RG16;
          info.fDefaultExternalFormat = GR_GL_RG;
          info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
          info.fDefaultColorType = GrColorType::kRG_1616;
          bool rg16Supported = false;
          if (GR_IS_GR_GL(standard)) {
              rg16Supported = version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg");
          } else if (GR_IS_GR_GL_ES(standard)) {
              rg16Supported = ctxInfo.hasExtension("GL_EXT_texture_norm16");
          }  // No WebGL support
  
          if (rg16Supported) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RG16;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG;
          }
  
          if (rg16Supported) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: GR_GL_RG16, Surface: kRG_1616
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRG_1616;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRG_1616, GrGLFormat::kRG16);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: GR_GL_RG16, Surface: kRG_1616, Data: kRG_1616
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRG_1616;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
                      ioFormat.fExternalTexImageFormat = GR_GL_RG;
                      ioFormat.fExternalReadFormat = GR_GL_RG;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: GR_GL_RG16, Surface: kRG_1616, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format: RGBA16
      {
          bool rgba16Support = false;
          if (GR_IS_GR_GL(standard)) {
              rgba16Support = version >= GR_GL_VER(3, 0);
          } else if (GR_IS_GR_GL_ES(standard)) {
              rgba16Support = ctxInfo.hasExtension("GL_EXT_texture_norm16");
          }  // No WebGL support
  
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16);
          info.fFormatType = FormatType::kNormalizedFixedPoint;
  
          info.fInternalFormatForRenderbuffer = GR_GL_RGBA16;
          info.fDefaultExternalFormat = GR_GL_RGBA;
          info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
          info.fDefaultColorType = GrColorType::kRGBA_16161616;
          if (rgba16Support) {
              info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA16;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RGBA16 : GR_GL_RGBA;
          }
  
          if (rgba16Support) {
              // Format: GR_GL_RGBA16, Surface: kRGBA_16161616
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRGBA_16161616;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRGBA_16161616, GrGLFormat::kRGBA16);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: GR_GL_RGBA16, Surface: kRGBA_16161616, Data: kRGBA_16161616
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_16161616;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
                      ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: GR_GL_RGBA16, Surface: kRGBA_16161616, Data: kRGBA_8888
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_8888;
                      ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      // Format:RG16F
      {
          bool rg16FTextureSupport = false;
          bool rg16FRenderTargetSupport = false;
          if (GR_IS_GR_GL(standard)) {
              if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_float")) {
                  rg16FTextureSupport = true;
                  rg16FRenderTargetSupport = true;
              }
          } else if (GR_IS_GR_GL_ES(standard)) {
              // It seems possible that a combination of GL_EXT_texture_rg and
              // GL_EXT_color_buffer_half_float might add this format to ES 2.0 but it is not entirely
              // clear. The latter mentions interaction but that may only be for renderbuffers as
              // neither adds the texture format explicitly.
              // GL_OES_texture_format_half_float makes no reference to RG formats.
              if (version >= GR_GL_VER(3, 0)) {
                  rg16FTextureSupport = true;
                  rg16FRenderTargetSupport = version >= GR_GL_VER(3, 2) ||
                                             ctxInfo.hasExtension("GL_EXT_color_buffer_float") ||
                                             ctxInfo.hasExtension("GL_EXT_color_buffer_half_float");
              }
          } else if (GR_IS_GR_WEBGL(standard)) {
              if (version >= GR_GL_VER(2, 0)) {
                  rg16FTextureSupport = true;
                  rg16FRenderTargetSupport = ctxInfo.hasExtension("GL_EXT_color_buffer_half_float") ||
                                             ctxInfo.hasExtension("EXT_color_buffer_half_float") ||
                                             ctxInfo.hasExtension("GL_EXT_color_buffer_float") ||
                                             ctxInfo.hasExtension("EXT_color_buffer_float");
              }
          }
  
          FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F);
          info.fFormatType = FormatType::kFloat;
          info.fInternalFormatForRenderbuffer = GR_GL_RG16F;
          info.fDefaultExternalFormat = GR_GL_RG;
          info.fDefaultExternalType = halfFloatType;
          info.fDefaultColorType = GrColorType::kRG_F16;
          if (rg16FTextureSupport) {
              info.fFlags |= FormatInfo::kTexturable_Flag;
              if (rg16FRenderTargetSupport) {
                  info.fFlags |= fpRenderFlags;
              }
          }
  
          if (texStorageSupported) {
              info.fFlags |= FormatInfo::kUseTexStorage_Flag;
              info.fInternalFormatForTexImageOrStorage = GR_GL_RG16F;
          } else {
              info.fInternalFormatForTexImageOrStorage =
                      texImageSupportsSizedInternalFormat ? GR_GL_RG16F : GR_GL_RG;
          }
  
          if (rg16FTextureSupport) {
              info.fColorTypeInfoCount = 1;
              info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
              int ctIdx = 0;
              // Format: GR_GL_RG16F, Surface: kRG_F16
              {
                  auto& ctInfo = info.fColorTypeInfos[ctIdx++];
                  ctInfo.fColorType = GrColorType::kRG_F16;
                  ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
                  this->setColorTypeFormat(GrColorType::kRG_F16, GrGLFormat::kRG16F);
  
                  // External IO ColorTypes:
                  ctInfo.fExternalIOFormatCount = 2;
                  ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
                          ctInfo.fExternalIOFormatCount);
                  int ioIdx = 0;
                  // Format: GR_GL_RG16F, Surface: kRG_F16, Data: kRG_F16
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRG_F16;
                      ioFormat.fExternalType = halfFloatType;
                      ioFormat.fExternalTexImageFormat = GR_GL_RG;
                      ioFormat.fExternalReadFormat = GR_GL_RG;
                      // Not guaranteed by ES/WebGL.
                      ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
                  }
  
                  // Format: GR_GL_RG16F, Surface: kRG_F16, Data: kRGBA_F32
                  {
                      auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
                      ioFormat.fColorType = GrColorType::kRGBA_F32;
                      ioFormat.fExternalType = GR_GL_FLOAT;
                      ioFormat.fExternalTexImageFormat = 0;
                      ioFormat.fExternalReadFormat = GR_GL_RGBA;
                  }
              }
          }
      }
  
      this->setupSampleCounts(ctxInfo, gli);
  
  #ifdef SK_DEBUG
      for (int i = 0; i < kGrGLColorFormatCount; ++i) {
          if (GrGLFormat::kUnknown == static_cast<GrGLFormat>(i)) {
              continue;
          }
          const auto& formatInfo = fFormatTable[i];
          // Make sure we didn't set fbo attachable with msaa and not fbo attachable.
          SkASSERT(!((formatInfo.fFlags & FormatInfo::kFBOColorAttachmentWithMSAA_Flag) &&
                    !(formatInfo.fFlags & FormatInfo::kFBOColorAttachment_Flag)));
  
          // Make sure we set all the formats' FormatType
          SkASSERT(formatInfo.fFormatType != FormatType::kUnknown);
  
          // Make sure if we added a ColorTypeInfo we filled it out
          for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
              const auto& ctInfo = formatInfo.fColorTypeInfos[j];
              SkASSERT(ctInfo.fColorType != GrColorType::kUnknown);
              // Seems silly to add a color type if we don't support any flags on it.
              SkASSERT(ctInfo.fFlags);
              // Make sure if we added any ExternalIOFormats we filled it out
              for (int k = 0; k < ctInfo.fExternalIOFormatCount; ++k) {
                  const auto& ioInfo = ctInfo.fExternalIOFormats[k];
                  SkASSERT(ioInfo.fColorType != GrColorType::kUnknown);
              }
          }
      }
  #endif
  }
  
  void GrGLCaps::setupSampleCounts(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
      GrGLStandard standard = ctxInfo.standard();
      // standard can be unused (optimized away) if SK_ASSUME_GL_ES is set
      sk_ignore_unused_variable(standard);
      GrGLVersion version = ctxInfo.version();
  
      for (int i = 0; i < kGrGLColorFormatCount; ++i) {
          if (FormatInfo::kFBOColorAttachmentWithMSAA_Flag & fFormatTable[i].fFlags) {
              // We assume that MSAA rendering is supported only if we support non-MSAA rendering.
              SkASSERT(FormatInfo::kFBOColorAttachment_Flag & fFormatTable[i].fFlags);
              if ((GR_IS_GR_GL(standard) &&
                    (version >= GR_GL_VER(4,2) ||
                     ctxInfo.hasExtension("GL_ARB_internalformat_query"))) ||
                  (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3,0))) {
                  int count;
                  GrGLFormat grGLFormat = static_cast<GrGLFormat>(i);
                  GrGLenum glFormat = this->getRenderbufferInternalFormat(grGLFormat);
                  GR_GL_GetInternalformativ(gli, GR_GL_RENDERBUFFER, glFormat,
                                            GR_GL_NUM_SAMPLE_COUNTS, 1, &count);
                  if (count) {
                      std::unique_ptr<int[]> temp(new int[count]);
                      GR_GL_GetInternalformativ(gli, GR_GL_RENDERBUFFER, glFormat, GR_GL_SAMPLES,
                                                count, temp.get());
                      // GL has a concept of MSAA rasterization with a single sample but we do not.
                      if (count && temp[count - 1] == 1) {
                          --count;
                          SkASSERT(!count || temp[count -1] > 1);
                      }
                      fFormatTable[i].fColorSampleCounts.setCount(count+1);
                      // We initialize our supported values with 1 (no msaa) and reverse the order
                      // returned by GL so that the array is ascending.
                      fFormatTable[i].fColorSampleCounts[0] = 1;
                      for (int j = 0; j < count; ++j) {
  #if defined(SK_BUILD_FOR_IOS) && TARGET_OS_SIMULATOR
                          // The iOS simulator is reporting incorrect values for sample counts,
                          // so force them to be a power of 2.
                          fFormatTable[i].fColorSampleCounts[j+1] = SkPrevPow2(temp[count - j - 1]);
  #else
                          fFormatTable[i].fColorSampleCounts[j+1] = temp[count - j - 1];
  #endif
                      }
                  }
              } else {
                  // Fake out the table using some semi-standard counts up to the max allowed sample
                  // count.
                  int maxSampleCnt = 1;
                  if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) {
                      GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &maxSampleCnt);
                  } else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) {
                      GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &maxSampleCnt);
                  }
                  // Chrome has a mock GL implementation that returns 0.
                  maxSampleCnt = std::max(1, maxSampleCnt);
  
                  static constexpr int kDefaultSamples[] = {1, 2, 4, 8};
                  int count = SK_ARRAY_COUNT(kDefaultSamples);
                  for (; count > 0; --count) {
                      if (kDefaultSamples[count - 1] <= maxSampleCnt) {
                          break;
                      }
                  }
                  if (count > 0) {
                      fFormatTable[i].fColorSampleCounts.append(count, kDefaultSamples);
                  }
              }
          } else if (FormatInfo::kFBOColorAttachment_Flag & fFormatTable[i].fFlags) {
              fFormatTable[i].fColorSampleCounts.setCount(1);
              fFormatTable[i].fColorSampleCounts[0] = 1;
          }
      }
  }
  
  bool GrGLCaps::canCopyTexSubImage(GrGLFormat dstFormat, bool dstHasMSAARenderBuffer,
                                    const GrTextureType* dstTypeIfTexture,
                                    GrGLFormat srcFormat, bool srcHasMSAARenderBuffer,
                                    const GrTextureType* srcTypeIfTexture) const {
      // When it comes to format types and component sizes the gl spec is fairly complex as
      // requirements differ depending on many properties (e.g. if the internalFormat was created with
      // a sized format or not). These affect the rules about which format types can be copied to
      // which other types. For now we are being more restrictive and requiring that the types must
      // match exactly.
      if (this->getFormatDefaultExternalType(dstFormat) !=
          this->getFormatDefaultExternalType(srcFormat)) {
          return false;
      }
  
      // Either both the src and dst formats need to be SRGB or both need to not be SRGB
      if (GrGLFormatIsSRGB(dstFormat) != GrGLFormatIsSRGB(srcFormat)) {
          return false;
      }
  
      if (GR_IS_GR_GL_ES(fStandard)) {
          // Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage
          // and BGRA isn't in the spec. There doesn't appear to be any extension that adds it.
          // ANGLE, for one, does not allow it. However, we've found it works on some drivers and
          // avoids bugs with using glBlitFramebuffer.
          if ((dstFormat == GrGLFormat::kBGRA8 || srcFormat == GrGLFormat::kBGRA8) &&
              !fAllowBGRA8CopyTexSubImage) {
              return false;
          }
  
          // Table 3.9 of the ES2 spec and 3.16 of ES3 spec indicates the supported internal base
          // formats with CopyTexSubImage. Each base format can be copied to itself or formats with
          // less channels.
          uint32_t dstChannels = GrGLFormatChannels(dstFormat);
          uint32_t srcChannels = GrGLFormatChannels(srcFormat);
          if (!dstChannels || !srcChannels) {
              // The formats don't represent color channels (i.e. may be depth stencil)
              return false;
          }
          // The dst channels have to be a subset of the srcChannels, except R, RG, or RGB, channels
          // can go to LUM. (See expansion of Table 3.9 in EXT_texture_rg).
          if ((dstChannels & srcChannels) != srcChannels) {
              if (dstChannels == kGray_SkColorChannelFlag ||
                  dstChannels == kGrayAlpha_SkColorChannelFlags) {
                  // The dst can't have gray if the src is alpha-only.
                  if (srcChannels == kAlpha_SkColorChannelFlag) {
                      return false;
                  }
              } else {
                  return false;
              }
          }
      }
  
      // CopyTexSubImage is invalid or doesn't copy what we want when we have msaa render buffers.
      if (dstHasMSAARenderBuffer || srcHasMSAARenderBuffer) {
          return false;
      }
  
      // CopyTex(Sub)Image writes to a texture and we have no way of dynamically wrapping a RT in a
      // texture.
      if (!dstTypeIfTexture) {
          return false;
      }
  
      // Check that we could wrap the source in an FBO, that the dst is not TEXTURE_EXTERNAL, that no
      // mirroring is required
      return this->canFormatBeFBOColorAttachment(srcFormat) &&
             (!srcTypeIfTexture || *srcTypeIfTexture != GrTextureType::kExternal) &&
             *dstTypeIfTexture != GrTextureType::kExternal;
  }
  
  bool GrGLCaps::canCopyAsBlit(GrGLFormat dstFormat, int dstSampleCnt,
                               const GrTextureType* dstTypeIfTexture,
                               GrGLFormat srcFormat, int srcSampleCnt,
                               const GrTextureType* srcTypeIfTexture,
                               const SkRect& srcBounds, bool srcBoundsExact,
                               const SkIRect& srcRect, const SkIPoint& dstPoint) const {
      auto blitFramebufferFlags = this->blitFramebufferSupportFlags();
      if (!this->canFormatBeFBOColorAttachment(dstFormat) ||
          !this->canFormatBeFBOColorAttachment(srcFormat)) {
          return false;
      }
  
      if (dstTypeIfTexture && *dstTypeIfTexture == GrTextureType::kExternal) {
          return false;
      }
      if (srcTypeIfTexture && *srcTypeIfTexture == GrTextureType::kExternal) {
          return false;
      }
  
      if (GrGLCaps::kNoSupport_BlitFramebufferFlag & blitFramebufferFlags) {
          return false;
      }
  
      if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) {
          if (srcSampleCnt > 1) {
              if (1 == dstSampleCnt) {
                  return false;
              }
              if (SkRect::Make(srcRect) != srcBounds || !srcBoundsExact) {
                  return false;
              }
          }
      }
  
      if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) {
          if (dstSampleCnt > 1) {
              return false;
          }
      }
  
      if (GrGLCaps::kNoFormatConversion_BlitFramebufferFlag & blitFramebufferFlags) {
          if (srcFormat != dstFormat) {
              return false;
          }
      } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) {
          if (srcSampleCnt > 1 && srcFormat != dstFormat) {
              return false;
          }
      }
  
      if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) {
          if (srcSampleCnt > 1) {
              if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) {
                  return false;
              }
          }
      }
      return true;
  }
  
  bool GrGLCaps::canCopyAsDraw(GrGLFormat dstFormat, bool srcIsTexturable) const {
      return this->isFormatRenderable(dstFormat, 1) && srcIsTexturable;
  }
  
  static bool has_msaa_render_buffer(const GrSurfaceProxy* surf, const GrGLCaps& glCaps) {
      const GrRenderTargetProxy* rt = surf->asRenderTargetProxy();
      if (!rt) {
          return false;
      }
      // A RT has a separate MSAA renderbuffer if:
      // 1) It's multisampled
      // 2) We're using an extension with separate MSAA renderbuffers
      // 3) It's not FBO 0, which is special and always auto-resolves
      return rt->numSamples() > 1 &&
             glCaps.usesMSAARenderBuffers() &&
             !rt->glRTFBOIDIs0();
  }
  
  bool GrGLCaps::onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
                                  const SkIRect& srcRect, const SkIPoint& dstPoint) const {
      int dstSampleCnt = 0;
      int srcSampleCnt = 0;
      if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) {
          dstSampleCnt = rtProxy->numSamples();
      }
      if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) {
          srcSampleCnt = rtProxy->numSamples();
      }
      SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy()));
      SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy()));
  
      const GrTextureProxy* dstTex = dst->asTextureProxy();
      const GrTextureProxy* srcTex = src->asTextureProxy();
  
      GrTextureType dstTexType;
      GrTextureType* dstTexTypePtr = nullptr;
      GrTextureType srcTexType;
      GrTextureType* srcTexTypePtr = nullptr;
      if (dstTex) {
          dstTexType = dstTex->textureType();
          dstTexTypePtr = &dstTexType;
      }
      if (srcTex) {
          srcTexType = srcTex->textureType();
          srcTexTypePtr = &srcTexType;
      }
  
      auto dstFormat = dst->backendFormat().asGLFormat();
      auto srcFormat = src->backendFormat().asGLFormat();
      return this->canCopyTexSubImage(dstFormat, has_msaa_render_buffer(dst, *this), dstTexTypePtr,
                                      srcFormat, has_msaa_render_buffer(src, *this), srcTexTypePtr) ||
             this->canCopyAsBlit(dstFormat, dstSampleCnt, dstTexTypePtr, srcFormat, srcSampleCnt,
                                 srcTexTypePtr, src->getBoundsRect(), src->priv().isExact(), srcRect,
                                 dstPoint) ||
             this->canCopyAsDraw(dstFormat, SkToBool(srcTex));
  }
  
  GrCaps::DstCopyRestrictions GrGLCaps::getDstCopyRestrictions(const GrRenderTargetProxy* src,
                                                               GrColorType colorType) const {
      // If the src is a texture, we can implement the blit as a draw assuming the config is
      // renderable.
      if (src->asTextureProxy() && !this->isFormatAsColorTypeRenderable(colorType,
                                                                        src->backendFormat())) {
          return {};
      }
  
      if (const auto* texProxy = src->asTextureProxy()) {
          if (texProxy->textureType() == GrTextureType::kExternal) {
              // Not supported for FBO blit or CopyTexSubImage. Caller will have to fall back to a
              // draw (if the source is also a texture).
              return {};
          }
      }
  
      // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are
      // possible and we return false to fallback to creating a render target dst for render-to-
      // texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo
      // creation. It isn't clear that avoiding temporary fbo creation is actually optimal.
      DstCopyRestrictions blitFramebufferRestrictions = {};
      if (src->numSamples() > 1 &&
          (this->blitFramebufferSupportFlags() & kResolveMustBeFull_BlitFrambufferFlag)) {
          blitFramebufferRestrictions.fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kYes;
          blitFramebufferRestrictions.fMustCopyWholeSrc = true;
          // Mirroring causes rects to mismatch later, don't allow it.
      } else if (src->numSamples() > 1 && (this->blitFramebufferSupportFlags() &
                                           kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) {
          blitFramebufferRestrictions.fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kYes;
      }
  
      auto srcFormat = src->backendFormat().asGLFormat();
      // Check for format issues with glCopyTexSubImage2D
      if (srcFormat == GrGLFormat::kBGRA8) {
          // glCopyTexSubImage2D doesn't work with this config. If the bgra can be used with fbo blit
          // then we set up for that, otherwise fail.
          if (this->canFormatBeFBOColorAttachment(srcFormat)) {
              return blitFramebufferRestrictions;
          }
          // Caller will have to use a draw.
          return {};
      }
  
      {
          bool srcIsMSAARenderbuffer = src->numSamples() > 1 &&
                                       this->usesMSAARenderBuffers();
          if (srcIsMSAARenderbuffer) {
              // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO
              // blit or fail.
              if (this->canFormatBeFBOColorAttachment(srcFormat)) {
                  return blitFramebufferRestrictions;
              }
              // Caller will have to use a draw.
              return {};
          }
      }
  
      // We'll do a CopyTexSubImage, no restrictions.
      return {};
  }
  
  void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
                                                   const GrContextOptions& contextOptions,
                                                   const GrGLInterface* glInterface,
                                                   GrShaderCaps* shaderCaps,
                                                   FormatWorkarounds* formatWorkarounds) {
      // A driver but on the nexus 6 causes incorrect dst copies when invalidate is called beforehand.
      // Thus we are disabling this extension for now on Adreno4xx devices.
      if (kAdreno430_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno4xx_other_GrGLRenderer == ctxInfo.renderer() ||
          fDriverBugWorkarounds.disable_discard_framebuffer) {
          fInvalidateFBType = kNone_InvalidateFBType;
      }
  
      // glClearTexImage seems to have a bug in NVIDIA drivers that was fixed sometime between
      // 340.96 and 367.57.
      if (GR_IS_GR_GL(ctxInfo.standard()) &&
          ctxInfo.driver() == kNVIDIA_GrGLDriver &&
          ctxInfo.driverVersion() < GR_GL_DRIVER_VER(367, 57, 0)) {
          fClearTextureSupport = false;
      }
  
  #ifdef SK_BUILD_FOR_MAC
      // Radeon MacBooks hit a crash in glReadPixels() when using geometry shaders.
      // http://skbug.com/8097
      if (kATI_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fGeometryShaderSupport = false;
      }
      // On at least some MacBooks, GLSL 4.0 geometry shaders break if we use invocations.
      shaderCaps->fGSInvocationsSupport = false;
  #endif
  
      // Qualcomm driver @103.0 has been observed to crash compiling ccpr geometry
      // shaders. @127.0 is the earliest verified driver to not crash.
      if (kQualcomm_GrGLDriver == ctxInfo.driver() &&
          ctxInfo.driverVersion() < GR_GL_DRIVER_VER(127, 0, 0)) {
          shaderCaps->fGeometryShaderSupport = false;
      }
  
      // glBlitFramebuffer seems to produce incorrect results on QC, Mali400, and Tegra3 but
      // glCopyTexSubImage2D works (even though there is no extension that specifically allows it).
      if (ctxInfo.vendor() == kQualcomm_GrGLVendor ||
          ctxInfo.renderer() == kMali4xx_GrGLRenderer ||
          ctxInfo.renderer() == kTegra_PreK1_GrGLRenderer) {
          fAllowBGRA8CopyTexSubImage = true;
      }
  
  #if defined(__has_feature)
  #if defined(SK_BUILD_FOR_MAC) && __has_feature(thread_sanitizer)
      // See skbug.com/7058
      fMapBufferType = kNone_MapBufferType;
      fMapBufferFlags = kNone_MapFlags;
      fTransferFromBufferToTextureSupport = false;
      fTransferFromSurfaceToBufferSupport = false;
      fTransferBufferType = TransferBufferType::kNone;
  #endif
  #endif
  
      // We found that the Galaxy J5 with an Adreno 306 running 6.0.1 has a bug where
      // GL_INVALID_OPERATION thrown by glDrawArrays when using a buffer that was mapped. The same bug
      // did not reproduce on a Nexus7 2013 with a 320 running Android M with driver 127.0. It's
      // unclear whether this really affects a wide range of devices.
      if (ctxInfo.renderer() == kAdreno3xx_GrGLRenderer &&
          ctxInfo.driverVersion() > GR_GL_DRIVER_VER(127, 0, 0)) {
          fMapBufferType = kNone_MapBufferType;
          fMapBufferFlags = kNone_MapFlags;
          fTransferFromBufferToTextureSupport = false;
          fTransferFromSurfaceToBufferSupport = false;
          fTransferBufferType = TransferBufferType::kNone;
      }
  
      // The TransferPixelsToTexture test fails on ANGLE.
      if (kANGLE_GrGLDriver == ctxInfo.driver()) {
          fTransferFromBufferToTextureSupport = false;
      }
  
      // Using MIPs on this GPU seems to be a source of trouble.
      if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer()) {
          fMipmapSupport = false;
      }
  
      // https://b.corp.google.com/issues/143074513
      if (kAdreno615_GrGLRenderer == ctxInfo.renderer()) {
          fMSFBOType = kNone_MSFBOType;
          fMSAAResolvesAutomatically = false;
      }
  
  #ifndef SK_BUILD_FOR_IOS
      if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer() ||
          kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() ||
          (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() &&
           ctxInfo.driver() != kChromium_GrGLDriver)) {
          fPerformColorClearsAsDraws = true;
      }
  #endif
  
      // A lot of GPUs have trouble with full screen clears (skbug.com/7195)
      if (kAMDRadeonHD7xxx_GrGLRenderer == ctxInfo.renderer() ||
          kAMDRadeonR9M4xx_GrGLRenderer == ctxInfo.renderer()) {
          fPerformColorClearsAsDraws = true;
      }
  
  #ifdef SK_BUILD_FOR_MAC
      // crbug.com/768134 - On MacBook Pros, the Intel Iris Pro doesn't always perform
      // full screen clears
      // crbug.com/773107 - On MacBook Pros, a wide range of Intel GPUs don't always
      // perform full screen clears.
      // Update on 4/4/2018 - This appears to be fixed on driver 10.30.12 on a macOS 10.13.2 on a
      // Retina MBP Early 2015 with Iris 6100. It is possibly fixed on earlier drivers as well.
      // crbug.com/1039912 - Crash rate in glClear spiked after OS update, affecting mostly
      //   Broadwell on 10.13+
      if (kIntel_GrGLVendor == ctxInfo.vendor() &&
          (ctxInfo.driverVersion() < GR_GL_DRIVER_VER(10, 30, 12) ||
           ctxInfo.renderer() == kIntelBroadwell_GrGLRenderer)) {
          fPerformColorClearsAsDraws = true;
      }
      // crbug.com/969609 - NVIDIA on Mac sometimes segfaults during glClear in chrome. It seems
      // mostly concentrated in 10.13/14, GT 650Ms, driver 12+. But there are instances of older
      // drivers and GTX 775s, so we'll start with a broader workaround.
      if (kNVIDIA_GrGLVendor == ctxInfo.vendor()) {
          fPerformColorClearsAsDraws = true;
      }
  #endif
  
      // See crbug.com/755871. This could probably be narrowed to just partial clears as the driver
      // bugs seems to involve clearing too much and not skipping the clear.
      // See crbug.com/768134. This is also needed for full clears and was seen on an nVidia K620
      // but only for D3D11 ANGLE.
      if (GrGLANGLEBackend::kD3D11 == ctxInfo.angleBackend()) {
          fPerformColorClearsAsDraws = true;
      }
  
      if (kAdreno430_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno4xx_other_GrGLRenderer == ctxInfo.renderer()) {
          // This is known to be fixed sometime between driver 145.0 and 219.0
          if (ctxInfo.driverVersion() <= GR_GL_DRIVER_VER(219, 0, 0)) {
              fPerformStencilClearsAsDraws = true;
          }
          fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = true;
      }
  
      if (fDriverBugWorkarounds.gl_clear_broken) {
          fPerformColorClearsAsDraws = true;
          fPerformStencilClearsAsDraws = true;
      }
  
      if (ctxInfo.vendor() == kQualcomm_GrGLVendor) {
          // It appears that all the Adreno GPUs have less than optimal performance when
          // drawing w/ large index buffers.
          fAvoidLargeIndexBufferDraws = true;
      }
  
      // This was reproduced on the following configurations:
      // - A Galaxy J5 (Adreno 306) running Android 6 with driver 140.0
      // - A Nexus 7 2013 (Adreno 320) running Android 5 with driver 104.0
      // - A Nexus 7 2013 (Adreno 320) running Android 6 with driver 127.0
      // - A Nexus 5 (Adreno 330) running Android 6 with driver 127.0
      // and not produced on:
      // - A Nexus 7 2013 (Adreno 320) running Android 4 with driver 53.0
      // The particular lines that get dropped from test images varies across different devices.
      if (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() &&
          ctxInfo.driverVersion() > GR_GL_DRIVER_VER(53, 0, 0)) {
          fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines = true;
      }
  
      // This was reproduced on a Pixel 1, but the unit test + config + options that exercise it are
      // only tested on very specific bots. The driver claims that ReadPixels is an invalid operation
      // when reading from an auto-resolving MSAA framebuffer that has stencil attached.
      if (kQualcomm_GrGLDriver == ctxInfo.driver()) {
          fDetachStencilFromMSAABuffersBeforeReadPixels = true;
      }
  
      // TODO: Don't apply this on iOS?
      if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
          // Our Chromebook with kPowerVRRogue_GrGLRenderer crashes on large instanced draws. The
          // current minimum number of instances observed to crash is somewhere between 2^14 and 2^15.
          // Keep the number of instances below 1000, just to be safe.
          fMaxInstancesPerDrawWithoutCrashing = 999;
      } else if (fDriverBugWorkarounds.disallow_large_instanced_draw) {
          fMaxInstancesPerDrawWithoutCrashing = 0x4000000;
      }
  
  #ifndef SK_BUILD_FOR_IOS
      if (ctxInfo.renderer() == kPowerVRRogue_GrGLRenderer) {
          // We saw this bug on a TecnoSpark 3 Pro with a PowerVR GE8300.
          // GL_VERSION: "OpenGL ES 3.2 build 1.10@51309121"
          // Possibly this could be more limited by driver version or HW generation.
          // When using samplers, we are seeing a bug where the gpu is sometimes not sampling the
          // correct mip level data. A workaround to this issue is that when binding a texture we also
          // set some texture state, and it seems like any inividual state works (e.g. min/mag filter,
          // base level, max level, etc.). Currently we just set the min filter level every time we
          // bind a texture as the workaround.
          fMustSetAnyTexParameterToEnableMipmapping = true;
          // ColorTypeBackendAllocationTest failed for kAlpha_8 and kGray_8 when using
          // GL_UNPACK_ROW_LENGTH. Perhaps this could be a more limited workaround by applying
          // only to single channel 8 bit unorm formats but we only have a monolithic query for this
          // support at present.
          fWritePixelsRowBytesSupport = false;
      }
  #endif
  
      // Texture uploads sometimes seem to be ignored to textures bound to FBOS on Tegra3.
      if (kTegra_PreK1_GrGLRenderer == ctxInfo.renderer()) {
          fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = true;
          fUseDrawInsteadOfAllRenderTargetWrites = true;
      }
  
  #ifdef SK_BUILD_FOR_MAC
      static constexpr bool isMAC = true;
  #else
      static constexpr bool isMAC = false;
  #endif
  
  #ifdef SK_BUILD_FOR_ANDROID
      // Older versions of Android have problems with setting GL_TEXTURE_BASE_LEVEL or
      // GL_TEXTURE_MAX_LEVEL on GL_TEXTURE_EXTERTNAL_OES textures. We just leave them as is and hope
      // the client never changes them either.
      fDontSetBaseOrMaxLevelForExternalTextures = true;
      // PowerVR can crash setting the levels on Android up to Q for any texture?
      // https://crbug.com/1123874
      if (ctxInfo.vendor() == kImagination_GrGLVendor) {
          fMipmapLevelControlSupport =  false;
      }
  #endif
  
      // We support manual mip-map generation (via iterative downsampling draw calls). This fixes
      // bugs on some cards/drivers that produce incorrect mip-maps for sRGB textures when using
      // glGenerateMipmap. Our implementation requires mip-level sampling control. Additionally,
      // it can be much slower (especially on mobile GPUs), so we opt-in only when necessary:
      if (fMipmapLevelControlSupport &&
          (contextOptions.fDoManualMipmapping ||
           (kIntel_GrGLVendor == ctxInfo.vendor()) ||
           (kNVIDIA_GrGLDriver == ctxInfo.driver() && isMAC) ||
           (kATI_GrGLVendor == ctxInfo.vendor()))) {
          fDoManualMipmapping = true;
      }
  
      // See http://crbug.com/710443
  #ifdef SK_BUILD_FOR_MAC
      if (kIntelBroadwell_GrGLRenderer == ctxInfo.renderer()) {
          fClearToBoundaryValuesIsBroken = true;
      }
  #endif
      if (kQualcomm_GrGLVendor == ctxInfo.vendor()) {
          fDrawArraysBaseVertexIsBroken = true;
      }
  
      // http://anglebug.com/4536
      if (ctxInfo.driver() == kANGLE_GrGLDriver &&
          ctxInfo.angleBackend() != GrGLANGLEBackend::kOpenGL) {
          fBaseVertexBaseInstanceSupport = false;
          fNativeDrawIndirectSupport = false;
          fMultiDrawType = MultiDrawType::kNone;
      }
  
      // http://anglebug.com/4538
      if (fBaseVertexBaseInstanceSupport && !fDrawInstancedSupport) {
          fBaseVertexBaseInstanceSupport = false;
          fNativeDrawIndirectSupport = false;
          fMultiDrawType = MultiDrawType::kNone;
      }
  
      // Currently the extension is advertised but fb fetch is broken on 500 series Adrenos like the
      // Galaxy S7.
      // TODO: Once this is fixed we can update the check here to look at a driver version number too.
      if (kAdreno530_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno5xx_other_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fFBFetchSupport = false;
      }
  
      // On the NexusS and GalaxyNexus, the use of 'any' causes the compilation error "Calls to any
      // function that may require a gradient calculation inside a conditional block may return
      // undefined results". This appears to be an issue with the 'any' call since even the simple
      // "result=black; if (any()) result=white;" code fails to compile.
      shaderCaps->fCanUseAnyFunctionInShader = kImagination_GrGLVendor != ctxInfo.vendor();
  
      // Known issue on at least some Intel platforms:
      // http://code.google.com/p/skia/issues/detail?id=946
      if (kIntel_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fFragCoordConventionsExtensionString = nullptr;
      }
  
      if (kTegra_PreK1_GrGLRenderer == ctxInfo.renderer()) {
          // The Tegra3 compiler will sometimes never return if we have min(abs(x), 1.0),
          // so we must do the abs first in a separate expression.
          shaderCaps->fCanUseMinAndAbsTogether = false;
  
          // Tegra3 fract() seems to trigger undefined behavior for negative values, so we
          // must avoid this condition.
          shaderCaps->fCanUseFractForNegativeValues = false;
  
          // Seeing crashes on Tegra3 with inlined functions that have early returns. Looks like the
          // do { ... break; } while (false); construct is causing a crash in the driver.
          shaderCaps->fCanUseDoLoops = false;
      }
  
      // On Intel GPU there is an issue where it reads the second argument to atan "- %s.x" as an int
      // thus must us -1.0 * %s.x to work correctly
      if (kIntel_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fMustForceNegatedAtanParamToFloat = true;
      }
  
      // On some Intel GPUs there is an issue where the driver outputs bogus values in the shader
      // when floor and abs are called on the same line. Thus we must execute an Op between them to
      // make sure the compiler doesn't re-inline them even if we break the calls apart.
      if (kIntel_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fMustDoOpBetweenFloorAndAbs = true;
      }
  
      // On Adreno devices with framebuffer fetch support, there is a bug where they always return
      // the original dst color when reading the outColor even after being written to. By using a
      // local outColor we can work around this bug.
      if (shaderCaps->fFBFetchSupport && kQualcomm_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fRequiresLocalOutputColorForFBFetch = true;
      }
  
      // Newer Mali GPUs do incorrect static analysis in specific situations: If there is uniform
      // color, and that uniform contains an opaque color, and the output of the shader is only based
      // on that uniform plus soemthing un-trackable (like a texture read), the compiler will deduce
      // that the shader always outputs opaque values. In that case, it appears to remove the shader
      // based blending code it normally injects, turning SrcOver into Src. To fix this, we always
      // insert an extra bit of math on the uniform that confuses the compiler just enough...
      if (kMaliT_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fMustObfuscateUniformColor = true;
      }
  
      // On Mali G series GPUs, applying transfer functions in the fragment shader with half-floats
      // produces answers that are much less accurate than expected/required. This forces full floats
      // for some intermediate values to get acceptable results.
      if (kMaliG_GrGLRenderer == ctxInfo.renderer()) {
          fShaderCaps->fColorSpaceMathNeedsFloat = true;
      }
  
  #ifdef SK_BUILD_FOR_WIN
      // Check for ANGLE on Windows, so we can workaround a bug in D3D itself (anglebug.com/2098).
      //
      // Basically, if a shader has a construct like:
      //
      // float x = someCondition ? someValue : 0;
      // float2 result = (0 == x) ? float2(x, x)
      //                          : float2(2 * x / x, 0);
      //
      // ... the compiler will produce an error 'NaN and infinity literals not allowed', even though
      // we've explicitly guarded the division with a check against zero. This manifests in much
      // more complex ways in some of our shaders, so we use this caps bit to add an epsilon value
      // to the denominator of divisions, even when we've added checks that the denominator isn't 0.
      if (kANGLE_GrGLDriver == ctxInfo.driver() || kChromium_GrGLDriver == ctxInfo.driver()) {
          shaderCaps->fMustGuardDivisionEvenAfterExplicitZeroCheck = true;
      }
  #endif
  
      if (ctxInfo.renderer() == kAdreno615_GrGLRenderer ||
          ctxInfo.renderer() == kAdreno630_GrGLRenderer ||
          ctxInfo.renderer() == kAdreno640_GrGLRenderer) {
          shaderCaps->fInBlendModesFailRandomlyForAllZeroVec = true;
      }
  
      // We've seen Adreno 3xx devices produce incorrect (flipped) values for gl_FragCoord, in some
      // (rare) situations. It's sporadic, and mostly on older drivers. Additionally, old Adreno
      // compilers (see crbug.com/skia/4078) crash when accessing .zw of gl_FragCoord, so just bypass
      // using gl_FragCoord at all to get around it.
      if (kAdreno3xx_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fCanUseFragCoord = false;
      }
  
      // gl_FragCoord has an incorrect subpixel offset on legacy Tegra hardware.
      if (kTegra_PreK1_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fCanUseFragCoord = false;
      }
  
      // On Mali G71, mediump ints don't appear capable of representing every integer beyond +/-2048.
      // (Are they implemented with fp16?)
      if (kARM_GrGLVendor == ctxInfo.vendor()) {
          shaderCaps->fIncompleteShortIntPrecision = true;
      }
  
      if (fDriverBugWorkarounds.add_and_true_to_loop_condition) {
          shaderCaps->fAddAndTrueToLoopCondition = true;
      }
  
      if (fDriverBugWorkarounds.unfold_short_circuit_as_ternary_operation) {
          shaderCaps->fUnfoldShortCircuitAsTernary = true;
      }
  
      if (fDriverBugWorkarounds.emulate_abs_int_function) {
          shaderCaps->fEmulateAbsIntFunction = true;
      }
  
      if (fDriverBugWorkarounds.rewrite_do_while_loops) {
          shaderCaps->fRewriteDoWhileLoops = true;
      }
  
      if (fDriverBugWorkarounds.remove_pow_with_constant_exponent) {
          shaderCaps->fRemovePowWithConstantExponent = true;
      }
  
      if (fDriverBugWorkarounds.disable_dual_source_blending_support) {
          shaderCaps->fDualSourceBlendingSupport = false;
      }
  
      if (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno4xx_other_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fMustWriteToFragColor = true;
      }
  
      // Disabling advanced blend on various platforms with major known issues. We also block Chrome
      // for now until its own denylists can be updated.
      if (kAdreno430_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno4xx_other_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno530_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno5xx_other_GrGLRenderer == ctxInfo.renderer() ||
          kIntel_GrGLDriver == ctxInfo.driver() ||
          kChromium_GrGLDriver == ctxInfo.driver()) {
          fBlendEquationSupport = kBasic_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kNotSupported_AdvBlendEqInteraction;
      }
  
      // Non-coherent advanced blend has an issue on NVIDIA pre 337.00.
      if (kNVIDIA_GrGLDriver == ctxInfo.driver() &&
          ctxInfo.driverVersion() < GR_GL_DRIVER_VER(337, 00, 0) &&
          kAdvanced_BlendEquationSupport == fBlendEquationSupport) {
          fBlendEquationSupport = kBasic_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kNotSupported_AdvBlendEqInteraction;
      }
  
      if (fDriverBugWorkarounds.disable_blend_equation_advanced) {
          fBlendEquationSupport = kBasic_BlendEquationSupport;
          shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kNotSupported_AdvBlendEqInteraction;
      }
  
      if (this->advancedBlendEquationSupport()) {
          if (kNVIDIA_GrGLDriver == ctxInfo.driver() &&
              ctxInfo.driverVersion() < GR_GL_DRIVER_VER(355, 00, 0)) {
              // Disable color-dodge and color-burn on pre-355.00 NVIDIA.
              fAdvBlendEqDisableFlags |= (1 << kColorDodge_GrBlendEquation) |
                                      (1 << kColorBurn_GrBlendEquation);
          }
          if (kARM_GrGLVendor == ctxInfo.vendor()) {
              // Disable color-burn on ARM until the fix is released.
              fAdvBlendEqDisableFlags |= (1 << kColorBurn_GrBlendEquation);
          }
      }
  
      // Many ES3 drivers only advertise the ES2 image_external extension, but support the _essl3
      // extension, and require that it be enabled to work with ESSL3. Other devices require the ES2
      // extension to be enabled, even when using ESSL3. Enabling both extensions fixes both cases.
      // skbug.com/7713
      if (ctxInfo.hasExtension("GL_OES_EGL_image_external") &&
          ctxInfo.glslGeneration() >= k330_GrGLSLGeneration &&
          !shaderCaps->fExternalTextureSupport) { // i.e. Missing the _essl3 extension
          shaderCaps->fExternalTextureSupport = true;
          shaderCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external";
          shaderCaps->fSecondExternalTextureExtensionString = "GL_OES_EGL_image_external_essl3";
      }
  
  #ifdef SK_BUILD_FOR_IOS
      // iOS drivers appear to implement TexSubImage by creating a staging buffer, and copying
      // UNPACK_ROW_LENGTH * height bytes. That's unsafe in several scenarios, and the simplest fix
      // is to just disable the feature.
      // https://github.com/flutter/flutter/issues/16718
      // https://bugreport.apple.com/web/?problemID=39948888
      fWritePixelsRowBytesSupport = false;
  #endif
  
      if (kIntel_GrGLVendor == ctxInfo.vendor() ||  // IntelIris640 drops draws completely.
          ctxInfo.renderer() == kMaliT_GrGLRenderer ||  // Some curves appear flat on GalaxyS6.
          ctxInfo.renderer() == kAdreno3xx_GrGLRenderer ||
          ctxInfo.renderer() == kAdreno430_GrGLRenderer ||
          ctxInfo.renderer() == kAdreno4xx_other_GrGLRenderer) {  // We get garbage on Adreno405.
          fDisableTessellationPathRenderer = true;
      }
  
      // http://skbug.com/9739
      bool isNVIDIAPascal =
              kNVIDIA_GrGLDriver == ctxInfo.driver() &&
              ctxInfo.hasExtension("GL_NV_conservative_raster_pre_snap_triangles") &&  // Pascal+.
              !ctxInfo.hasExtension("GL_NV_conservative_raster_underestimation");  // Volta+.
      if (isNVIDIAPascal && ctxInfo.driverVersion() < GR_GL_DRIVER_VER(440, 00, 0)) {
          if (GR_IS_GR_GL(ctxInfo.standard())) {
              // glMemoryBarrier wasn't around until version 4.2.
              if (ctxInfo.version() >= GR_GL_VER(4,2)) {
                  fRequiresManualFBBarrierAfterTessellatedStencilDraw = true;
              } else {
                  shaderCaps->fMaxTessellationSegments = 0;
              }
          } else {
              // glMemoryBarrier wasn't around until es version 3.1.
              if (ctxInfo.version() >= GR_GL_VER(3,1)) {
                  fRequiresManualFBBarrierAfterTessellatedStencilDraw = true;
              } else {
                  shaderCaps->fMaxTessellationSegments = 0;
              }
          }
      }
  
      if (kQualcomm_GrGLDriver == ctxInfo.driver()) {
          // Qualcomm fails to link programs with tessellation and does not give an error message.
          // http://skbug.com/9740
          shaderCaps->fMaxTessellationSegments = 0;
      }
  
  #ifdef SK_BUILD_FOR_WIN
      // glDrawElementsIndirect fails GrMeshTest on every Win10 Intel bot.
      if (ctxInfo.driver() == kIntel_GrGLDriver ||
          (ctxInfo.driver() == kANGLE_GrGLDriver &&
           ctxInfo.angleVendor() == GrGLANGLEVendor::kIntel &&
           ctxInfo.angleBackend() == GrGLANGLEBackend::kOpenGL)) {
          fNativeDrawIndexedIndirectIsBroken = true;
          fUseClientSideIndirectBuffers = true;
      }
  #endif
  
      // PowerVRGX6250 drops every pixel if we modify the sample mask while color writes are disabled.
      if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
          fNeverDisableColorWrites = true;
          shaderCaps->fMustWriteToFragColor = true;
      }
  
      // It appears that Qualcomm drivers don't actually support
      // GL_NV_shader_noperspective_interpolation in ES 3.00 or 3.10 shaders, only 3.20.
      // https://crbug.com/986581
      if (kQualcomm_GrGLVendor == ctxInfo.vendor() &&
          k320es_GrGLSLGeneration != ctxInfo.glslGeneration()) {
          shaderCaps->fNoPerspectiveInterpolationSupport = false;
      }
  
      // We disable srgb write control for Adreno4xx devices.
      // see: https://bug.skia.org/5329
      if (kAdreno430_GrGLRenderer == ctxInfo.renderer() ||
          kAdreno4xx_other_GrGLRenderer == ctxInfo.renderer()) {
          fSRGBWriteControl = false;
      }
  
      // MacPro devices with AMD cards fail to create MSAA sRGB render buffers.
  #if defined(SK_BUILD_FOR_MAC)
      formatWorkarounds->fDisableSRGBRenderWithMSAAForMacAMD = kATI_GrGLVendor == ctxInfo.vendor();
  #endif
  
      // Command buffer fails glTexSubImage2D with type == GL_HALF_FLOAT_OES if a GL_RGBA16F texture
      // is created with glTexStorage2D. See crbug.com/1008003.
      formatWorkarounds->fDisableRGBA16FTexStorageForCrBug1008003 =
              kChromium_GrGLDriver == ctxInfo.driver() && ctxInfo.version() < GR_GL_VER(3, 0);
  
  #if defined(SK_BUILD_FOR_WIN)
      // On Intel Windows ES contexts it seems that using texture storage with BGRA causes
      // problems with cross-context SkImages.
      formatWorkarounds->fDisableBGRATextureStorageForIntelWindowsES =
              kIntel_GrGLDriver == ctxInfo.driver() && GR_IS_GR_GL_ES(ctxInfo.standard());
  #endif
  
      // On the Intel Iris 6100, interacting with LUM16F seems to confuse the driver. After
      // writing to/reading from a LUM16F texture reads from/writes to other formats behave
      // erratically.
      // All Adrenos claim to support LUM16F but don't appear to actually do so.
      // The failing devices/gpus were: Nexus5/Adreno330, Nexus5x/Adreno418, Pixel/Adreno530,
      // Pixel2XL/Adreno540 and Pixel3/Adreno630
      formatWorkarounds->fDisableLuminance16F = kIntelBroadwell_GrGLRenderer == ctxInfo.renderer() ||
                                                ctxInfo.vendor() == kQualcomm_GrGLVendor;
  
  #ifdef SK_BUILD_FOR_MAC
      // On a MacBookPro 11.5 running MacOS 10.13 with a Radeon M370X the TransferPixelsFrom test
      // fails when transferring out from a GL_RG8 texture using GL_RG/GL_UNSIGNED_BYTE.
      // The same error also occurs in MacOS 10.15 with a Radeon Pro 5300M.
      formatWorkarounds->fDisallowDirectRG8ReadPixels =
              ctxInfo.renderer() == kAMDRadeonR9M3xx_GrGLRenderer ||
              ctxInfo.renderer() == kAMDRadeonPro5xxx_GrGLRenderer ||
              ctxInfo.renderer() == kAMDRadeonProVegaxx_GrGLRenderer;
  #endif
  
  #ifdef SK_BUILD_FOR_ANDROID
      // We don't usually use glTexStorage() on Android for performance reasons. (crbug.com/945506).
      // On a NVIDIA Shield TV running Android 7.0 creating a texture with glTexImage2D() with
      // internal format GL_LUMINANCE8 fails. However, it succeeds with glTexStorage2D().
      //
      // Additionally, on the Nexus 9 running Android 6.0.1 formats added by GL_EXT_texture_rg and
      // GL_EXT_texture_norm16 cause errors if they are created with glTexImage2D() with
      // an unsized internal format. We wouldn't normally do that but Chrome can limit us
      // artificially to ES2. (crbug.com/1003481)
      if (kNVIDIA_GrGLVendor == ctxInfo.vendor()) {
          formatWorkarounds->fDontDisableTexStorageOnAndroid = true;
      }
  #endif
  
      // https://github.com/flutter/flutter/issues/38700
      if (kAndroidEmulator_GrGLDriver == ctxInfo.driver()) {
          shaderCaps->fNoDefaultPrecisionForExternalSamplers = true;
      }
  
      // http://skbug.com/9491: Nexus5 produces rendering artifacts when we use QCOM_tiled_rendering.
      if (kAdreno3xx_GrGLRenderer == ctxInfo.renderer()) {
          fTiledRenderingSupport = false;
      }
      // https://github.com/flutter/flutter/issues/47164
      // https://github.com/flutter/flutter/issues/47804
      if (fTiledRenderingSupport && (!glInterface->fFunctions.fStartTiling ||
                                     !glInterface->fFunctions.fEndTiling)) {
          // Some devices expose the QCOM tiled memory extension string but don't actually provide the
          // start and end tiling functions (see above flutter bugs). To work around this, the funcs
          // are marked optional in the interface generator, but we turn off the tiled rendering cap
          // if they aren't provided. This disabling is in driver workarounds so that SKQP will still
          // fail on devices that advertise the extension w/o the functions.
          fTiledRenderingSupport = false;
      }
  
      if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9) {
          formatWorkarounds->fDisallowBGRA8ReadPixels = true;
      }
  
      // We disable MSAA for all Intel GPUs. Before Gen9, performance was very bad. Even with Gen9,
      // we've seen driver crashes in the wild. We don't have data on Gen11 yet.
      // (crbug.com/527565, crbug.com/983926)
      if (kIntel_GrGLVendor == ctxInfo.vendor()) {
          fMSFBOType = kNone_MSFBOType;
      }
  
      // ANGLE doesn't support do-while loops
      if (kANGLE_GrGLDriver == ctxInfo.driver()) {
          shaderCaps->fCanUseDoLoops = false;
      }
  
      // ANGLE's D3D9 backend + AMD GPUs are flaky with program binary caching (skbug.com/10395)
      if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9 &&
          ctxInfo.angleVendor() == GrGLANGLEVendor::kAMD) {
          fProgramBinarySupport = false;
      }
  
      // Two Adreno 530 devices (LG G6 and OnePlus 3T) appear to have driver bugs that are corrupting
      // SkSL::Program memory. To get better/different crash reports, disable node-pooling, so that
      // program allocations aren't reused.  (crbug.com/1147008, crbug.com/1164271)
      if (kAdreno530_GrGLRenderer == ctxInfo.renderer()) {
          shaderCaps->fUseNodePools = false;
      }
  
      // skbug.com/11204. Avoid recursion issue in GrSurfaceContext::writePixels.
      if (fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO) {
          fReuseScratchTextures = false;
      }
  }
  
  void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
      if (options.fDisableDriverCorrectnessWorkarounds) {
          SkASSERT(!fDoManualMipmapping);
          SkASSERT(!fClearToBoundaryValuesIsBroken);
          SkASSERT(0 == fMaxInstancesPerDrawWithoutCrashing);
          SkASSERT(!fDrawArraysBaseVertexIsBroken);
          SkASSERT(!fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO);
          SkASSERT(!fUseDrawInsteadOfAllRenderTargetWrites);
          SkASSERT(!fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines);
          SkASSERT(!fDetachStencilFromMSAABuffersBeforeReadPixels);
          SkASSERT(!fDontSetBaseOrMaxLevelForExternalTextures);
          SkASSERT(!fNeverDisableColorWrites);
      }
      if (options.fShaderCacheStrategy < GrContextOptions::ShaderCacheStrategy::kBackendBinary) {
          fProgramBinarySupport = false;
      }
  
      switch (options.fSkipGLErrorChecks) {
          case GrContextOptions::Enable::kNo:
              fSkipErrorChecks = false;
              break;
          case GrContextOptions::Enable::kYes:
              fSkipErrorChecks = true;
              break;
          case GrContextOptions::Enable::kDefault:
              break;
      }
  }
  
  bool GrGLCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
      if (fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO) {
          if (auto tex = static_cast<const GrGLTexture*>(surface->asTexture())) {
              if (tex->hasBaseLevelBeenBoundToFBO()) {
                  return false;
              }
          }
      }
      if (auto rt = surface->asRenderTarget()) {
          if (fUseDrawInsteadOfAllRenderTargetWrites) {
              return false;
          }
          if (rt->numSamples() > 1 && this->usesMSAARenderBuffers()) {
              return false;
          }
          return SkToBool(surface->asTexture());
      }
      return true;
  }
  
  GrCaps::SurfaceReadPixelsSupport GrGLCaps::surfaceSupportsReadPixels(
          const GrSurface* surface) const {
      if (auto tex = static_cast<const GrGLTexture*>(surface->asTexture())) {
          // We don't support reading pixels directly from EXTERNAL textures as it would require
          // binding the texture to a FBO. For now we also disallow reading back directly
          // from compressed textures.
          if (tex->target() == GR_GL_TEXTURE_EXTERNAL || GrGLFormatIsCompressed(tex->format())) {
              return SurfaceReadPixelsSupport::kCopyToTexture2D;
          }
      } else if (auto rt = static_cast<const GrGLRenderTarget*>(surface->asRenderTarget())) {
          // glReadPixels does not allow reading back from a MSAA framebuffer. If the underlying
          // GrSurface doesn't have a second FBO to resolve to then we must make a copy.
          if (rt->numSamples() > 1 && rt->textureFBOID() == GrGLRenderTarget::kUnresolvableFBOID) {
              return SurfaceReadPixelsSupport::kCopyToTexture2D;
          }
      }
      return SurfaceReadPixelsSupport::kSupported;
  }
  
  size_t offset_alignment_for_transfer_buffer(GrGLenum externalType) {
      // This switch is derived from a table titled "Pixel data type parameter values and the
      // corresponding GL data types" in the OpenGL spec (Table 8.2 in OpenGL 4.5).
      switch (externalType) {
          case GR_GL_UNSIGNED_BYTE:                   return sizeof(GrGLubyte);
          case GR_GL_BYTE:                            return sizeof(GrGLbyte);
          case GR_GL_UNSIGNED_SHORT:                  return sizeof(GrGLushort);
          case GR_GL_SHORT:                           return sizeof(GrGLshort);
          case GR_GL_UNSIGNED_INT:                    return sizeof(GrGLuint);
          case GR_GL_INT:                             return sizeof(GrGLint);
          case GR_GL_HALF_FLOAT:                      return sizeof(GrGLhalf);
          case GR_GL_HALF_FLOAT_OES:                  return sizeof(GrGLhalf);
          case GR_GL_FLOAT:                           return sizeof(GrGLfloat);
          case GR_GL_UNSIGNED_SHORT_5_6_5:            return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_SHORT_4_4_4_4:          return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_SHORT_5_5_5_1:          return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_INT_2_10_10_10_REV:     return sizeof(GrGLuint);
  #if 0  // GL types we currently don't use. Here for future reference.
          case GR_GL_UNSIGNED_BYTE_3_3_2:             return sizeof(GrGLubyte);
          case GR_GL_UNSIGNED_BYTE_2_3_3_REV:         return sizeof(GrGLubyte);
          case GR_GL_UNSIGNED_SHORT_5_6_5_REV:        return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_SHORT_4_4_4_4_REV:      return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_SHORT_1_5_5_5_REV:      return sizeof(GrGLushort);
          case GR_GL_UNSIGNED_INT_8_8_8_8:            return sizeof(GrGLuint);
          case GR_GL_UNSIGNED_INT_8_8_8_8_REV:        return sizeof(GrGLuint);
          case GR_GL_UNSIGNED_INT_10_10_10_2:         return sizeof(GrGLuint);
          case GR_GL_UNSIGNED_INT_24_8:               return sizeof(GrGLuint);
          case GR_GL_UNSIGNED_INT_10F_11F_11F_REV:    return sizeof(GrGLuint);
          case GR_GL_UNSIGNED_INT_5_9_9_9_REV:        return sizeof(GrGLuint);
          // This one is not corresponding to a GL data type and the spec just says it is 4.
          case GR_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:  return 4;
  #endif
          default:                                    return 0;
      }
  }
  
  GrCaps::SupportedRead GrGLCaps::onSupportedReadPixelsColorType(
          GrColorType srcColorType, const GrBackendFormat& srcBackendFormat,
          GrColorType dstColorType) const {
  
      SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat);
      if (compression != SkImage::CompressionType::kNone) {
          return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
                                                          : GrColorType::kRGBA_8888,
                   offset_alignment_for_transfer_buffer(GR_GL_UNSIGNED_BYTE) };
      }
  
      // We first try to find a supported read pixels GrColorType that matches the requested
      // dstColorType. If that doesn't exists we will use any valid read pixels GrColorType.
      GrCaps::SupportedRead fallbackRead = {GrColorType::kUnknown, 0};
      const auto& formatInfo = this->getFormatInfo(srcBackendFormat.asGLFormat());
      bool foundSrcCT = false;
      for (int i = 0; !foundSrcCT && i < formatInfo.fColorTypeInfoCount; ++i) {
          if (formatInfo.fColorTypeInfos[i].fColorType == srcColorType) {
              const ColorTypeInfo& ctInfo = formatInfo.fColorTypeInfos[i];
              foundSrcCT = true;
              for (int j = 0; j < ctInfo.fExternalIOFormatCount; ++j) {
                  const auto& ioInfo = ctInfo.fExternalIOFormats[j];
                  if (ioInfo.fExternalReadFormat != 0) {
                      if (formatInfo.fHaveQueriedImplementationReadSupport ||
                          !ioInfo.fRequiresImplementationReadQuery) {
                          GrGLenum transferOffsetAlignment =
                                  offset_alignment_for_transfer_buffer(ioInfo.fExternalType);
                          if (ioInfo.fColorType == dstColorType) {
                              return {dstColorType, transferOffsetAlignment};
                          }
                          // Currently we just pick the first supported format that we find as our
                          // fallback.
                          if (fallbackRead.fColorType == GrColorType::kUnknown) {
                              fallbackRead = {ioInfo.fColorType, transferOffsetAlignment};
                          }
                      }
                  }
              }
          }
      }
      return fallbackRead;
  }
  
  GrCaps::SupportedWrite GrGLCaps::supportedWritePixelsColorType(GrColorType surfaceColorType,
                                                                 const GrBackendFormat& surfaceFormat,
                                                                 GrColorType srcColorType) const {
      // We first try to find a supported write pixels GrColorType that matches the data's
      // srcColorType. If that doesn't exists we will use any supported GrColorType.
      GrColorType fallbackCT = GrColorType::kUnknown;
      const auto& formatInfo = this->getFormatInfo(surfaceFormat.asGLFormat());
      bool foundSurfaceCT = false;
      for (int i = 0; !foundSurfaceCT && i < formatInfo.fColorTypeInfoCount; ++i) {
          if (formatInfo.fColorTypeInfos[i].fColorType == surfaceColorType) {
              const ColorTypeInfo& ctInfo = formatInfo.fColorTypeInfos[i];
              foundSurfaceCT = true;
              for (int j = 0; j < ctInfo.fExternalIOFormatCount; ++j) {
                  const auto& ioInfo = ctInfo.fExternalIOFormats[j];
                  if (ioInfo.fExternalTexImageFormat != 0) {
                      if (ioInfo.fColorType == srcColorType) {
                          return {srcColorType, 1};
                      }
                      // Currently we just pick the first supported format that we find as our
                      // fallback.
                      if (fallbackCT == GrColorType::kUnknown) {
                          fallbackCT = ioInfo.fColorType;
                      }
                  }
              }
          }
      }
      return {fallbackCT, 1};
  }
  
  bool GrGLCaps::onIsWindowRectanglesSupportedForRT(const GrBackendRenderTarget& backendRT) const {
      GrGLFramebufferInfo fbInfo;
      SkAssertResult(backendRT.getGLFramebufferInfo(&fbInfo));
      // Window Rectangles are not supported for FBO 0;
      return fbInfo.fFBOID != 0;
  }
  
  bool GrGLCaps::isFormatSRGB(const GrBackendFormat& format) const {
      return format.asGLFormat() == GrGLFormat::kSRGB8_ALPHA8;
  }
  
  bool GrGLCaps::isFormatTexturable(const GrBackendFormat& format) const {
      if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) {
          return false;
      }
      return this->isFormatTexturable(format.asGLFormat());
  }
  
  bool GrGLCaps::isFormatTexturable(GrGLFormat format) const {
      const FormatInfo& info = this->getFormatInfo(format);
      return SkToBool(info.fFlags & FormatInfo::kTexturable_Flag);
  }
  
  bool GrGLCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format,
                                               int sampleCount) const {
      if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) {
          return false;
      }
      if (format.textureType() == GrTextureType::kExternal) {
          return false;
      }
      auto f = format.asGLFormat();
      const FormatInfo& info = this->getFormatInfo(f);
      if (!SkToBool(info.colorTypeFlags(ct) & ColorTypeInfo::kRenderable_Flag)) {
          return false;
      }
  
      return this->isFormatRenderable(f, sampleCount);
  }
  
  bool GrGLCaps::isFormatRenderable(const GrBackendFormat& format, int sampleCount) const {
      if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) {
          return false;
      }
      if (format.textureType() == GrTextureType::kExternal) {
          return false;
      }
      return this->isFormatRenderable(format.asGLFormat(), sampleCount);
  }
  
  int GrGLCaps::getRenderTargetSampleCount(int requestedCount, GrGLFormat format) const {
      const FormatInfo& info = this->getFormatInfo(format);
  
      int count = info.fColorSampleCounts.count();
      if (!count) {
          return 0;
      }
  
      requestedCount = std::max(1, requestedCount);
      if (1 == requestedCount) {
          return info.fColorSampleCounts[0] == 1 ? 1 : 0;
      }
  
      for (int i = 0; i < count; ++i) {
          if (info.fColorSampleCounts[i] >= requestedCount) {
              int count = info.fColorSampleCounts[i];
              if (fDriverBugWorkarounds.max_msaa_sample_count_4) {
                  count = std::min(count, 4);
              }
              return count;
          }
      }
      return 0;
  }
  
  int GrGLCaps::maxRenderTargetSampleCount(GrGLFormat format) const {
      const FormatInfo& info = this->getFormatInfo(format);
      const auto& table = info.fColorSampleCounts;
      if (!table.count()) {
          return 0;
      }
      int count = table[table.count() - 1];
      if (fDriverBugWorkarounds.max_msaa_sample_count_4) {
          count = std::min(count, 4);
      }
      return count;
  }
  
  bool GrGLCaps::canFormatBeFBOColorAttachment(GrGLFormat format) const {
      return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kFBOColorAttachment_Flag);
  }
  
  bool GrGLCaps::isFormatCopyable(const GrBackendFormat& format) const {
      // In GL we have three ways to be able to copy. CopyTexImage, blit, and draw. CopyTexImage
      // requires the src to be an FBO attachment, blit requires both src and dst to be FBO
      // attachments, and draw requires the dst to be an FBO attachment. Thus to copy from and to
      // the same config, we need that config to be bindable to an FBO.
      return this->canFormatBeFBOColorAttachment(format.asGLFormat());
  }
  
  bool GrGLCaps::formatSupportsTexStorage(GrGLFormat format) const {
      return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kUseTexStorage_Flag);
  }
  
  bool GrGLCaps::shouldQueryImplementationReadSupport(GrGLFormat format) const {
      const auto& formatInfo = const_cast<GrGLCaps*>(this)->getFormatInfo(format);
      if (!formatInfo.fHaveQueriedImplementationReadSupport) {
          // Check whether we will actually learn anything useful.
          bool needQuery = false;
          for (int i = 0; i < formatInfo.fColorTypeInfoCount && !needQuery; ++i) {
              const auto& surfCTInfo = formatInfo.fColorTypeInfos[i];
              for (int j = 0; j < surfCTInfo.fExternalIOFormatCount; ++j) {
                  if (surfCTInfo.fExternalIOFormats[j].fRequiresImplementationReadQuery) {
                      needQuery = true;
                      break;
                  }
              }
          }
          if (!needQuery) {
              // Pretend we already checked it.
              const_cast<FormatInfo&>(formatInfo).fHaveQueriedImplementationReadSupport = true;
          }
      }
      return !formatInfo.fHaveQueriedImplementationReadSupport;
  }
  
  void GrGLCaps::didQueryImplementationReadSupport(GrGLFormat format,
                                                   GrGLenum readFormat,
                                                   GrGLenum readType) const {
      auto& formatInfo = const_cast<GrGLCaps*>(this)->getFormatInfo(format);
      for (int i = 0; i < formatInfo.fColorTypeInfoCount; ++i) {
          auto& surfCTInfo = formatInfo.fColorTypeInfos[i];
          for (int j = 0; j < surfCTInfo.fExternalIOFormatCount; ++j) {
              auto& readCTInfo = surfCTInfo.fExternalIOFormats[j];
              if (readCTInfo.fRequiresImplementationReadQuery) {
                  if (readCTInfo.fExternalReadFormat != readFormat ||
                      readCTInfo.fExternalType != readType) {
                      // Don't zero out fExternalType. It's also used for writing data to the texture!
                      readCTInfo.fExternalReadFormat = 0;
                  }
              }
          }
      }
      formatInfo.fHaveQueriedImplementationReadSupport = true;
  }
  
  bool GrGLCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
                                                   const GrBackendFormat& format) const {
      GrGLFormat glFormat = format.asGLFormat();
      const auto& info = this->getFormatInfo(glFormat);
      for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
          if (info.fColorTypeInfos[i].fColorType == ct) {
              return true;
          }
      }
      return false;
  }
  
  GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct) const {
      auto format = this->getFormatFromColorType(ct);
      if (format == GrGLFormat::kUnknown) {
          return {};
      }
      return GrBackendFormat::MakeGL(GrGLFormatToEnum(format), GR_GL_TEXTURE_2D);
  }
  
  GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
          SkImage::CompressionType compressionType) const {
      switch (compressionType) {
          case SkImage::CompressionType::kNone:
              return {};
          case SkImage::CompressionType::kETC2_RGB8_UNORM:
              // if ETC2 is available default to that format
              if (this->isFormatTexturable(GrGLFormat::kCOMPRESSED_RGB8_ETC2)) {
                  return GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGB8_ETC2, GR_GL_TEXTURE_2D);
              }
              if (this->isFormatTexturable(GrGLFormat::kCOMPRESSED_ETC1_RGB8)) {
                  return GrBackendFormat::MakeGL(GR_GL_COMPRESSED_ETC1_RGB8, GR_GL_TEXTURE_2D);
              }
              return {};
          case SkImage::CompressionType::kBC1_RGB8_UNORM:
              if (this->isFormatTexturable(GrGLFormat::kCOMPRESSED_RGB8_BC1)) {
                  return GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
                                                 GR_GL_TEXTURE_2D);
              }
              return {};
          case SkImage::CompressionType::kBC1_RGBA8_UNORM:
              if (this->isFormatTexturable(GrGLFormat::kCOMPRESSED_RGBA8_BC1)) {
                  return GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
                                                 GR_GL_TEXTURE_2D);
              }
              return {};
      }
  
      SkUNREACHABLE;
  }
  
  GrSwizzle GrGLCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
      GrGLFormat glFormat = format.asGLFormat();
      const auto& info = this->getFormatInfo(glFormat);
      for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
          const auto& ctInfo = info.fColorTypeInfos[i];
          if (ctInfo.fColorType == colorType) {
              return ctInfo.fReadSwizzle;
          }
      }
      SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.", colorType,
                   glFormat);
      return {};
  }
  
  GrSwizzle GrGLCaps::getWriteSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
      const auto& info = this->getFormatInfo(format.asGLFormat());
      for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
          const auto& ctInfo = info.fColorTypeInfos[i];
          if (ctInfo.fColorType == colorType) {
              return ctInfo.fWriteSwizzle;
          }
      }
      SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.", colorType,
                   format.asGLFormat());
      return {};
  }
  
  GrDstSampleType GrGLCaps::onGetDstSampleTypeForProxy(const GrRenderTargetProxy* rt) const {
      if (rt->asTextureProxy()) {
          return GrDstSampleType::kAsSelfTexture;
      }
      return GrDstSampleType::kAsTextureCopy;
  }
  
  uint64_t GrGLCaps::computeFormatKey(const GrBackendFormat& format) const {
      auto glFormat = format.asGLFormat();
      return (uint64_t)(glFormat);
  }
  
  GrProgramDesc GrGLCaps::makeDesc(GrRenderTarget* /* rt */,
                                   const GrProgramInfo& programInfo,
                                   ProgramDescOverrideFlags overrideFlags) const {
      SkASSERT(overrideFlags == ProgramDescOverrideFlags::kNone);
      GrProgramDesc desc;
      GrProgramDesc::Build(&desc, programInfo, *this);
      return desc;
  }
  
  #if GR_TEST_UTILS
  std::vector<GrCaps::TestFormatColorTypeCombination> GrGLCaps::getTestingCombinations() const {
      std::vector<GrCaps::TestFormatColorTypeCombination> combos = {
          { GrColorType::kAlpha_8,
            GrBackendFormat::MakeGL(GR_GL_ALPHA8, GR_GL_TEXTURE_2D) },
          { GrColorType::kAlpha_8,
            GrBackendFormat::MakeGL(GR_GL_R8, GR_GL_TEXTURE_2D) },
          { GrColorType::kBGR_565,
            GrBackendFormat::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_2D) },
          { GrColorType::kABGR_4444,
            GrBackendFormat::MakeGL(GR_GL_RGBA4, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_8888,
            GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_8888_SRGB,
            GrBackendFormat::MakeGL(GR_GL_SRGB8_ALPHA8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGB_888x,
            GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGB_888x,
            GrBackendFormat::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGB_888x,
            GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGB8_ETC2, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGB_888x,
            GrBackendFormat::MakeGL(GR_GL_COMPRESSED_ETC1_RGB8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGB_888x,
            GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_8888,
            GrBackendFormat::MakeGL(GR_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GR_GL_TEXTURE_2D) },
          { GrColorType::kRG_88,
            GrBackendFormat::MakeGL(GR_GL_RG8, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_1010102,
            GrBackendFormat::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_2D) },
          { GrColorType::kGray_8,
            GrBackendFormat::MakeGL(GR_GL_LUMINANCE8, GR_GL_TEXTURE_2D) },
          { GrColorType::kGray_8,
            GrBackendFormat::MakeGL(GR_GL_R8, GR_GL_TEXTURE_2D) },
          { GrColorType::kGrayAlpha_88,
            GrBackendFormat::MakeGL(GR_GL_LUMINANCE8_ALPHA8, GR_GL_TEXTURE_2D) },
          { GrColorType::kAlpha_F16,
            GrBackendFormat::MakeGL(GR_GL_R16F, GR_GL_TEXTURE_2D) },
          { GrColorType::kAlpha_F16,
            GrBackendFormat::MakeGL(GR_GL_LUMINANCE16F, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_F16,
            GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_F16_Clamped,
            GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D) },
          { GrColorType::kAlpha_16,
            GrBackendFormat::MakeGL(GR_GL_R16, GR_GL_TEXTURE_2D) },
          { GrColorType::kRG_1616,
            GrBackendFormat::MakeGL(GR_GL_RG16, GR_GL_TEXTURE_2D) },
          { GrColorType::kRGBA_16161616,
            GrBackendFormat::MakeGL(GR_GL_RGBA16, GR_GL_TEXTURE_2D) },
          { GrColorType::kRG_F16,
            GrBackendFormat::MakeGL(GR_GL_RG16F, GR_GL_TEXTURE_2D) },
      };
  
      if (GR_IS_GR_GL(fStandard)) {
          combos.push_back({ GrColorType::kBGRA_8888,
                             GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_2D) });
          combos.push_back({ GrColorType::kBGRA_1010102,
                             GrBackendFormat::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_2D) });
      } else {
          SkASSERT(GR_IS_GR_GL_ES(fStandard) || GR_IS_GR_WEBGL(fStandard));
  
          combos.push_back({ GrColorType::kBGRA_8888,
                             GrBackendFormat::MakeGL(GR_GL_BGRA8, GR_GL_TEXTURE_2D) });
      }
      if (this->rectangleTextureSupport()) {
          size_t count2D = combos.size();
          for (size_t i = 0; i < count2D; ++i) {
              auto combo2D = combos[i];
              GrGLenum formatEnum = GrGLFormatToEnum(combo2D.fFormat.asGLFormat());
              combos.push_back({combo2D.fColorType,
                                GrBackendFormat::MakeGL(formatEnum, GR_GL_TEXTURE_RECTANGLE)});
          }
      }
      return combos;
  }
  #endif
  