mesa/glformats: make _mesa_gles_error_check_format_and_type() more consistent
[mesa.git] / src / mesa / main / glformats.c
index 057a5d160b4145d22ed6e3a6ffed5a2d7baf3dad..1d528f4bff54b609a78600190c6980e4e687fccd 100644 (file)
@@ -28,6 +28,7 @@
 #include "context.h"
 #include "glformats.h"
 #include "formats.h"
+#include "texcompress.h"
 #include "enums.h"
 
 enum {
@@ -186,7 +187,7 @@ get_map_idx(GLenum value)
       return IDX_RG;
    default:
       _mesa_problem(NULL, "Unexpected inFormat %s",
-                    _mesa_lookup_enum_by_nr(value));
+                    _mesa_enum_to_string(value));
       return 0;
    }
 }
@@ -216,8 +217,8 @@ _mesa_compute_component_mapping(GLenum inFormat, GLenum outFormat, GLubyte *map)
 
 #if 0
    printf("from %x/%s to %x/%s map %d %d %d %d %d %d\n",
-         inFormat, _mesa_lookup_enum_by_nr(inFormat),
-         outFormat, _mesa_lookup_enum_by_nr(outFormat),
+         inFormat, _mesa_enum_to_string(inFormat),
+         outFormat, _mesa_enum_to_string(outFormat),
          map[0],
          map[1],
          map[2],
@@ -494,7 +495,8 @@ _mesa_bytes_per_pixel(GLenum format, GLenum type)
       else
          return -1;
    case GL_UNSIGNED_INT_24_8_EXT:
-      if (format == GL_DEPTH_STENCIL_EXT)
+      if (format == GL_DEPTH_COMPONENT ||
+          format == GL_DEPTH_STENCIL_EXT)
          return sizeof(GLuint);
       else
          return -1;
@@ -544,6 +546,7 @@ _mesa_bytes_per_vertex_attrib(GLint comps, GLenum type)
    case GL_FLOAT:
       return comps * sizeof(GLfloat);
    case GL_HALF_FLOAT_ARB:
+   case GL_HALF_FLOAT_OES:
       return comps * sizeof(GLhalfARB);
    case GL_DOUBLE:
       return comps * sizeof(GLdouble);
@@ -560,6 +563,8 @@ _mesa_bytes_per_vertex_attrib(GLint comps, GLenum type)
          return sizeof(GLuint);
       else
          return -1;
+   case GL_UNSIGNED_INT64_ARB:
+      return comps * 8;
    default:
       return -1;
    }
@@ -820,6 +825,112 @@ _mesa_is_enum_format_signed_int(GLenum format)
    }
 }
 
+/**
+ * Test if the given format is an ASTC 2D format.
+ */
+static bool
+is_astc_2d_format(GLenum internalFormat)
+{
+   switch (internalFormat) {
+   case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+   case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+      return true;
+   default:
+      return false;
+   }
+}
+
+/**
+ * Test if the given format is an ASTC 3D format.
+ */
+static bool
+is_astc_3d_format(GLenum internalFormat)
+{
+   switch (internalFormat) {
+   case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES:
+   case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES:
+   case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES:
+   case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES:
+   case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES:
+   case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES:
+   case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES:
+   case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES:
+   case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES:
+   case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES:
+      return true;
+   default:
+      return false;
+   }
+}
+
+/**
+ * Test if the given format is an ASTC format.
+ */
+GLboolean
+_mesa_is_astc_format(GLenum internalFormat)
+{
+   return is_astc_2d_format(internalFormat) ||
+          is_astc_3d_format(internalFormat);
+}
+
+/**
+ * Test if the given format is an ETC2 format.
+ */
+GLboolean
+_mesa_is_etc2_format(GLenum internalFormat)
+{
+   switch (internalFormat) {
+   case GL_COMPRESSED_RGB8_ETC2:
+   case GL_COMPRESSED_SRGB8_ETC2:
+   case GL_COMPRESSED_RGBA8_ETC2_EAC:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+   case GL_COMPRESSED_R11_EAC:
+   case GL_COMPRESSED_RG11_EAC:
+   case GL_COMPRESSED_SIGNED_R11_EAC:
+   case GL_COMPRESSED_SIGNED_RG11_EAC:
+   case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+   case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+      return true;
+   default:
+      return false;
+   }
+}
 
 /**
  * Test if the given format is an integer (non-normalized) format.
@@ -1003,6 +1114,37 @@ _mesa_is_color_format(GLenum format)
       case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
       case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
       case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
+      case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+      case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+      case GL_ATC_RGB_AMD:
+      case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+      case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
       /* generic integer formats */
       case GL_RED_INTEGER_EXT:
       case GL_GREEN_INTEGER_EXT:
@@ -1202,66 +1344,20 @@ _mesa_is_depth_or_stencil_format(GLenum format)
 GLboolean
 _mesa_is_compressed_format(const struct gl_context *ctx, GLenum format)
 {
+   mesa_format m_format = _mesa_glenum_to_compressed_format(format);
+
+   /* Some formats in this switch have an equivalent mesa_format_layout
+    * to the compressed formats in the layout switch below and thus
+    * must be handled first.
+    */
    switch (format) {
-   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-      /* Assume that the ANGLE flag will always be set if the EXT flag is set.
-       */
-      return ctx->Extensions.ANGLE_texture_compression_dxt;
    case GL_RGB_S3TC:
    case GL_RGB4_S3TC:
    case GL_RGBA_S3TC:
    case GL_RGBA4_S3TC:
-      return _mesa_is_desktop_gl(ctx) &&
-         ctx->Extensions.ANGLE_texture_compression_dxt;
-   case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-      return _mesa_is_desktop_gl(ctx)
-         && ctx->Extensions.EXT_texture_sRGB
-         && ctx->Extensions.EXT_texture_compression_s3tc;
-   case GL_COMPRESSED_RGB_FXT1_3DFX:
-   case GL_COMPRESSED_RGBA_FXT1_3DFX:
-      return _mesa_is_desktop_gl(ctx)
-         && ctx->Extensions.TDFX_texture_compression_FXT1;
-   case GL_COMPRESSED_RED_RGTC1:
-   case GL_COMPRESSED_SIGNED_RED_RGTC1:
-   case GL_COMPRESSED_RG_RGTC2:
-   case GL_COMPRESSED_SIGNED_RG_RGTC2:
-      return _mesa_is_desktop_gl(ctx)
-         && ctx->Extensions.ARB_texture_compression_rgtc;
-   case GL_COMPRESSED_LUMINANCE_LATC1_EXT:
-   case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
-   case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
-   case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
-      return ctx->API == API_OPENGL_COMPAT
-         && ctx->Extensions.EXT_texture_compression_latc;
+      return _mesa_has_S3_s3tc(ctx);
    case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI:
-      return ctx->API == API_OPENGL_COMPAT
-         && ctx->Extensions.ATI_texture_compression_3dc;
-   case GL_ETC1_RGB8_OES:
-      return _mesa_is_gles(ctx)
-         && ctx->Extensions.OES_compressed_ETC1_RGB8_texture;
-   case GL_COMPRESSED_RGB8_ETC2:
-   case GL_COMPRESSED_SRGB8_ETC2:
-   case GL_COMPRESSED_RGBA8_ETC2_EAC:
-   case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-   case GL_COMPRESSED_R11_EAC:
-   case GL_COMPRESSED_RG11_EAC:
-   case GL_COMPRESSED_SIGNED_R11_EAC:
-   case GL_COMPRESSED_SIGNED_RG11_EAC:
-   case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-   case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-      return _mesa_is_gles3(ctx) || ctx->Extensions.ARB_ES3_compatibility;
-   case GL_COMPRESSED_RGBA_BPTC_UNORM:
-   case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
-   case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
-   case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
-      return _mesa_is_desktop_gl(ctx) &&
-         ctx->Extensions.ARB_texture_compression_bptc;
+      return _mesa_has_ATI_texture_compression_3dc(ctx);
    case GL_PALETTE4_RGB8_OES:
    case GL_PALETTE4_RGBA8_OES:
    case GL_PALETTE4_R5_G6_B5_OES:
@@ -1273,14 +1369,132 @@ _mesa_is_compressed_format(const struct gl_context *ctx, GLenum format)
    case GL_PALETTE8_RGBA4_OES:
    case GL_PALETTE8_RGB5_A1_OES:
       return ctx->API == API_OPENGLES;
+   }
+
+   switch (_mesa_get_format_layout(m_format)) {
+   case MESA_FORMAT_LAYOUT_S3TC:
+      if (!_mesa_is_format_srgb(m_format)) {
+         return _mesa_has_EXT_texture_compression_s3tc(ctx);
+      } else {
+         return (_mesa_has_EXT_texture_sRGB(ctx) ||
+            _mesa_has_EXT_texture_compression_s3tc_srgb(ctx)) &&
+            _mesa_has_EXT_texture_compression_s3tc(ctx);
+      }
+   case MESA_FORMAT_LAYOUT_FXT1:
+      return _mesa_has_3DFX_texture_compression_FXT1(ctx);
+   case MESA_FORMAT_LAYOUT_RGTC:
+      return _mesa_has_ARB_texture_compression_rgtc(ctx) ||
+             _mesa_has_EXT_texture_compression_rgtc(ctx);
+   case MESA_FORMAT_LAYOUT_LATC:
+      return _mesa_has_EXT_texture_compression_latc(ctx);
+   case MESA_FORMAT_LAYOUT_ETC1:
+      return _mesa_has_OES_compressed_ETC1_RGB8_texture(ctx);
+   case MESA_FORMAT_LAYOUT_ETC2:
+      return _mesa_is_gles3(ctx) || _mesa_has_ARB_ES3_compatibility(ctx);
+   case MESA_FORMAT_LAYOUT_BPTC:
+      return _mesa_has_ARB_texture_compression_bptc(ctx) ||
+             _mesa_has_EXT_texture_compression_bptc(ctx);
+   case MESA_FORMAT_LAYOUT_ASTC:
+      return _mesa_has_KHR_texture_compression_astc_ldr(ctx);
+   case MESA_FORMAT_LAYOUT_ATC:
+      return _mesa_has_AMD_compressed_ATC_texture(ctx);
    default:
       return GL_FALSE;
    }
 }
 
+/**
+ * Test if the given format represents an sRGB format.
+ * \param format the GL format (can be an internal format)
+ * \return GL_TRUE if format is sRGB, GL_FALSE otherwise
+ */
+GLboolean
+_mesa_is_srgb_format(GLenum format)
+{
+   switch (format) {
+   case GL_SRGB:
+   case GL_SRGB8:
+   case GL_SRGB_ALPHA:
+   case GL_SRGB8_ALPHA8:
+   case GL_COMPRESSED_SRGB:
+   case GL_COMPRESSED_SRGB_ALPHA:
+   case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+   case GL_COMPRESSED_SRGB8_ETC2:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+   case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+   case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+   case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+      return GL_TRUE;
+   default:
+      break;
+   }
+
+   return GL_FALSE;
+}
+
+/**
+ * Convert various unpack formats to the corresponding base format.
+ */
+GLenum
+_mesa_unpack_format_to_base_format(GLenum format)
+{
+   switch(format) {
+   case GL_RED_INTEGER:
+      return GL_RED;
+   case GL_GREEN_INTEGER:
+      return GL_GREEN;
+   case GL_BLUE_INTEGER:
+      return GL_BLUE;
+   case GL_ALPHA_INTEGER:
+      return GL_ALPHA;
+   case GL_RG_INTEGER:
+      return GL_RG;
+   case GL_RGB_INTEGER:
+      return GL_RGB;
+   case GL_RGBA_INTEGER:
+      return GL_RGBA;
+   case GL_BGR_INTEGER:
+      return GL_BGR;
+   case GL_BGRA_INTEGER:
+      return GL_BGRA;
+   case GL_LUMINANCE_INTEGER_EXT:
+      return GL_LUMINANCE;
+   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
+      return GL_LUMINANCE_ALPHA;
+   case GL_RED:
+   case GL_GREEN:
+   case GL_BLUE:
+   case GL_RG:
+   case GL_RGB:
+   case GL_RGBA:
+   case GL_BGR:
+   case GL_BGRA:
+   case GL_ALPHA:
+   case GL_LUMINANCE:
+   case GL_LUMINANCE_ALPHA:
+   default:
+      return format;
+   }
+}
 
 /**
- * Convert various base formats to the cooresponding integer format.
+ * Convert various base formats to the corresponding integer format.
  */
 GLenum
 _mesa_base_format_to_integer_format(GLenum format)
@@ -1326,6 +1540,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
    case GL_TEXTURE_RED_TYPE:
    case GL_RENDERBUFFER_RED_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+   case GL_INTERNALFORMAT_RED_SIZE:
+   case GL_INTERNALFORMAT_RED_TYPE:
       if (base_format == GL_RED ||
          base_format == GL_RG ||
          base_format == GL_RGB ||
@@ -1337,6 +1553,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
    case GL_TEXTURE_GREEN_TYPE:
    case GL_RENDERBUFFER_GREEN_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+   case GL_INTERNALFORMAT_GREEN_SIZE:
+   case GL_INTERNALFORMAT_GREEN_TYPE:
       if (base_format == GL_RG ||
          base_format == GL_RGB ||
          base_format == GL_RGBA) {
@@ -1347,6 +1565,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
    case GL_TEXTURE_BLUE_TYPE:
    case GL_RENDERBUFFER_BLUE_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+   case GL_INTERNALFORMAT_BLUE_SIZE:
+   case GL_INTERNALFORMAT_BLUE_TYPE:
       if (base_format == GL_RGB ||
          base_format == GL_RGBA) {
         return GL_TRUE;
@@ -1356,6 +1576,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
    case GL_TEXTURE_ALPHA_TYPE:
    case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+   case GL_INTERNALFORMAT_ALPHA_SIZE:
+   case GL_INTERNALFORMAT_ALPHA_TYPE:
       if (base_format == GL_RGBA ||
          base_format == GL_ALPHA ||
          base_format == GL_LUMINANCE_ALPHA) {
@@ -1379,6 +1601,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
    case GL_TEXTURE_DEPTH_TYPE:
    case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+   case GL_INTERNALFORMAT_DEPTH_SIZE:
+   case GL_INTERNALFORMAT_DEPTH_TYPE:
       if (base_format == GL_DEPTH_STENCIL ||
          base_format == GL_DEPTH_COMPONENT) {
         return GL_TRUE;
@@ -1386,6 +1610,8 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
       return GL_FALSE;
    case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
    case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+   case GL_INTERNALFORMAT_STENCIL_SIZE:
+   case GL_INTERNALFORMAT_STENCIL_TYPE:
       if (base_format == GL_DEPTH_STENCIL ||
          base_format == GL_STENCIL_INDEX) {
         return GL_TRUE;
@@ -1401,32 +1627,6 @@ _mesa_base_format_has_channel(GLenum base_format, GLenum pname)
 }
 
 
-/**
- * Returns the number of channels/components for a base format.
- */
-GLint
-_mesa_base_format_component_count(GLenum base_format)
-{
-   switch (base_format) {
-   case GL_RED:
-   case GL_ALPHA:
-   case GL_INTENSITY:
-   case GL_DEPTH_COMPONENT:
-      return 1;
-   case GL_RG:
-   case GL_LUMINANCE_ALPHA:
-   case GL_DEPTH_STENCIL:
-      return 2;
-   case GL_RGB:
-      return 3;
-   case GL_RGBA:
-      return 4;
-   default:
-      return -1;
-   }
-}
-
-
 /**
  * If format is a generic compressed format, return the corresponding
  * non-compressed format.  For other formats, return the format as-is.
@@ -1608,7 +1808,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          break; /* OK */
       }
       if (format == GL_RGB_INTEGER_EXT &&
-          ctx->Extensions.ARB_texture_rgb10_a2ui) {
+          _mesa_has_texture_rgb10_a2ui(ctx)) {
          break; /* OK */
       }
       return GL_INVALID_OPERATION;
@@ -1623,7 +1823,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          break; /* OK */
       }
       if ((format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) &&
-          ctx->Extensions.ARB_texture_rgb10_a2ui) {
+          _mesa_has_texture_rgb10_a2ui(ctx)) {
          break; /* OK */
       }
       return GL_INVALID_OPERATION;
@@ -1637,7 +1837,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          break; /* OK */
       }
       if ((format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) &&
-          ctx->Extensions.ARB_texture_rgb10_a2ui) {
+          _mesa_has_texture_rgb10_a2ui(ctx)) {
          break; /* OK */
       }
       if (type == GL_UNSIGNED_INT_2_10_10_10_REV && format == GL_RGB &&
@@ -1647,13 +1847,17 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
       return GL_INVALID_OPERATION;
 
    case GL_UNSIGNED_INT_24_8:
+      /* Depth buffer OK to read in OpenGL ES (NV_read_depth). */
+      if (ctx->API == API_OPENGLES2 && format == GL_DEPTH_COMPONENT)
+         return GL_NO_ERROR;
+
       if (format != GL_DEPTH_STENCIL) {
          return GL_INVALID_OPERATION;
       }
       return GL_NO_ERROR;
 
    case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-      if (!ctx->Extensions.ARB_depth_buffer_float) {
+      if (!_mesa_has_float_depth_buffer(ctx)) {
          return GL_INVALID_ENUM;
       }
       if (format != GL_DEPTH_STENCIL) {
@@ -1662,7 +1866,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
       return GL_NO_ERROR;
 
    case GL_UNSIGNED_INT_10F_11F_11F_REV:
-      if (!ctx->Extensions.EXT_packed_float) {
+      if (!_mesa_has_packed_float(ctx)) {
          return GL_INVALID_ENUM;
       }
       if (format != GL_RGB) {
@@ -1680,8 +1884,9 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          return GL_NO_ERROR;
       case GL_RG:
       case GL_RED:
-        if (_mesa_is_gles3(ctx) || ctx->Extensions.ARB_texture_rg)
+         if (_mesa_has_rg_textures(ctx))
             return GL_NO_ERROR;
+         /* fallthrough */
       default:
          return GL_INVALID_OPERATION;
       }
@@ -1734,8 +1939,8 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          }
 
       case GL_RG:
-        if (!ctx->Extensions.ARB_texture_rg)
-           return GL_INVALID_ENUM;
+         if (!_mesa_has_rg_textures(ctx))
+            return GL_INVALID_ENUM;
          switch (type) {
             case GL_BYTE:
             case GL_UNSIGNED_BYTE:
@@ -1770,10 +1975,10 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
                return (ctx->API == API_OPENGLES2)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             case GL_UNSIGNED_INT_5_9_9_9_REV:
-               return ctx->Extensions.EXT_texture_shared_exponent
+               return _mesa_has_texture_shared_exponent(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             case GL_UNSIGNED_INT_10F_11F_11F_REV:
-               return ctx->Extensions.EXT_packed_float
+               return _mesa_has_packed_float(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1841,7 +2046,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
          }
 
       case GL_YCBCR_MESA:
-         if (!ctx->Extensions.MESA_ycbcr_texture)
+         if (!_mesa_has_MESA_ycbcr_texture(ctx))
             return GL_INVALID_ENUM;
          if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
              type == GL_UNSIGNED_SHORT_8_8_REV_MESA)
@@ -1852,7 +2057,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
       case GL_DEPTH_STENCIL:
          if (type == GL_UNSIGNED_INT_24_8)
             return GL_NO_ERROR;
-         else if (ctx->Extensions.ARB_depth_buffer_float &&
+         else if (_mesa_has_float_depth_buffer(ctx) &&
              type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV)
             return GL_NO_ERROR;
          else
@@ -1871,8 +2076,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_UNSIGNED_SHORT:
             case GL_INT:
             case GL_UNSIGNED_INT:
-               return (ctx->Version >= 30 ||
-                       ctx->Extensions.EXT_texture_integer)
+               return _mesa_has_integer_textures(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1886,14 +2090,13 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_UNSIGNED_SHORT:
             case GL_INT:
             case GL_UNSIGNED_INT:
-               return (ctx->Version >= 30 ||
-                       ctx->Extensions.EXT_texture_integer)
+               return _mesa_has_integer_textures(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             case GL_UNSIGNED_BYTE_3_3_2:
             case GL_UNSIGNED_BYTE_2_3_3_REV:
             case GL_UNSIGNED_SHORT_5_6_5:
             case GL_UNSIGNED_SHORT_5_6_5_REV:
-               return ctx->Extensions.ARB_texture_rgb10_a2ui
+               return _mesa_has_texture_rgb10_a2ui(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1908,8 +2111,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_INT:
             case GL_UNSIGNED_INT:
             /* NOTE: no packed formats w/ BGR format */
-               return (ctx->Version >= 30 ||
-                       ctx->Extensions.EXT_texture_integer)
+               return _mesa_has_integer_textures(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1924,8 +2126,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_UNSIGNED_SHORT:
             case GL_INT:
             case GL_UNSIGNED_INT:
-               return (ctx->Version >= 30 ||
-                       ctx->Extensions.EXT_texture_integer)
+               return _mesa_has_integer_textures(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             case GL_UNSIGNED_SHORT_4_4_4_4:
             case GL_UNSIGNED_SHORT_4_4_4_4_REV:
@@ -1935,7 +2136,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_UNSIGNED_INT_8_8_8_8_REV:
             case GL_UNSIGNED_INT_10_10_10_2:
             case GL_UNSIGNED_INT_2_10_10_10_REV:
-               return ctx->Extensions.ARB_texture_rgb10_a2ui
+               return _mesa_has_texture_rgb10_a2ui(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1950,7 +2151,7 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
             case GL_UNSIGNED_SHORT:
             case GL_INT:
             case GL_UNSIGNED_INT:
-               return ctx->Extensions.EXT_texture_integer
+               return _mesa_has_integer_textures(ctx)
                   ? GL_NO_ERROR : GL_INVALID_ENUM;
             default:
                return GL_INVALID_ENUM;
@@ -1969,12 +2170,18 @@ _mesa_error_check_format_and_type(const struct gl_context *ctx,
  * \return error code, or GL_NO_ERROR.
  */
 GLenum
-_mesa_es_error_check_format_and_type(GLenum format, GLenum type,
+_mesa_es_error_check_format_and_type(const struct gl_context *ctx,
+                                     GLenum format, GLenum type,
                                      unsigned dimensions)
 {
    GLboolean type_valid = GL_TRUE;
 
    switch (format) {
+   case GL_RED:
+   case GL_RG:
+      if (!_mesa_has_rg_textures(ctx))
+         return GL_INVALID_VALUE;
+      /* fallthrough */
    case GL_ALPHA:
    case GL_LUMINANCE:
    case GL_LUMINANCE_ALPHA:
@@ -1996,7 +2203,8 @@ _mesa_es_error_check_format_and_type(GLenum format, GLenum type,
                     || type == GL_UNSIGNED_SHORT_5_5_5_1
                     || type == GL_FLOAT
                     || type == GL_HALF_FLOAT_OES
-                    || type == GL_UNSIGNED_INT_2_10_10_10_REV);
+                    || (_mesa_has_texture_type_2_10_10_10_REV(ctx) &&
+                        type == GL_UNSIGNED_INT_2_10_10_10_REV));
       break;
 
    case GL_DEPTH_COMPONENT:
@@ -2031,96 +2239,713 @@ _mesa_es_error_check_format_and_type(GLenum format, GLenum type,
    return type_valid ? GL_NO_ERROR : GL_INVALID_OPERATION;
 }
 
-
 /**
- * Do error checking of format/type combinations for OpenGL ES 3
- * glTex[Sub]Image.
- * \return error code, or GL_NO_ERROR.
+ * Return the simple base format for a given internal texture format.
+ * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA.
+ *
+ * \param ctx GL context.
+ * \param internalFormat the internal texture format token or 1, 2, 3, or 4.
+ *
+ * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
+ * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum.
+ *
+ * This is the format which is used during texture application (i.e. the
+ * texture format and env mode determine the arithmetic used.
  */
-GLenum
-_mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
-                                      GLenum format, GLenum type,
-                                      GLenum internalFormat)
+GLint
+_mesa_base_tex_format(const struct gl_context *ctx, GLint internalFormat)
 {
-   switch (format) {
+   switch (internalFormat) {
+   case GL_ALPHA:
+   case GL_ALPHA4:
+   case GL_ALPHA8:
+   case GL_ALPHA12:
+   case GL_ALPHA16:
+      return (ctx->API != API_OPENGL_CORE) ? GL_ALPHA : -1;
+   case 1:
+   case GL_LUMINANCE:
+   case GL_LUMINANCE4:
+   case GL_LUMINANCE8:
+   case GL_LUMINANCE12:
+   case GL_LUMINANCE16:
+      return (ctx->API != API_OPENGL_CORE) ? GL_LUMINANCE : -1;
+   case 2:
+   case GL_LUMINANCE_ALPHA:
+   case GL_LUMINANCE4_ALPHA4:
+   case GL_LUMINANCE6_ALPHA2:
+   case GL_LUMINANCE8_ALPHA8:
+   case GL_LUMINANCE12_ALPHA4:
+   case GL_LUMINANCE12_ALPHA12:
+   case GL_LUMINANCE16_ALPHA16:
+      return (ctx->API != API_OPENGL_CORE) ? GL_LUMINANCE_ALPHA : -1;
+   case GL_INTENSITY:
+   case GL_INTENSITY4:
+   case GL_INTENSITY8:
+   case GL_INTENSITY12:
+   case GL_INTENSITY16:
+      return (ctx->API != API_OPENGL_CORE) ? GL_INTENSITY : -1;
+   case 3:
+      return (ctx->API != API_OPENGL_CORE) ? GL_RGB : -1;
+   case GL_RGB:
+   case GL_R3_G3_B2:
+   case GL_RGB4:
+   case GL_RGB5:
+   case GL_RGB8:
+   case GL_RGB10:
+   case GL_RGB12:
+   case GL_RGB16:
+      return GL_RGB;
+   case 4:
+      return (ctx->API != API_OPENGL_CORE) ? GL_RGBA : -1;
    case GL_RGBA:
-      switch (type) {
-      case GL_UNSIGNED_BYTE:
-         switch (internalFormat) {
-         case GL_RGBA:
-         case GL_RGBA8:
-         case GL_RGB5_A1:
-         case GL_RGBA4:
-         case GL_SRGB8_ALPHA8_EXT:
-            break;
-         default:
-            return GL_INVALID_OPERATION;
-         }
-         break;
-
-      case GL_BYTE:
-         if (internalFormat != GL_RGBA8_SNORM)
-            return GL_INVALID_OPERATION;
-         break;
-
-      case GL_UNSIGNED_SHORT_4_4_4_4:
-         switch (internalFormat) {
-         case GL_RGBA:
-         case GL_RGBA4:
-            break;
-         default:
-            return GL_INVALID_OPERATION;
-         }
-         break;
-
-      case GL_UNSIGNED_SHORT_5_5_5_1:
-         switch (internalFormat) {
-         case GL_RGBA:
-         case GL_RGB5_A1:
-            break;
-         default:
-            return GL_INVALID_OPERATION;
-         }
-         break;
-
-      case GL_UNSIGNED_INT_2_10_10_10_REV:
-         switch (internalFormat) {
-         case GL_RGBA: /* GL_EXT_texture_type_2_10_10_10_REV */
-         case GL_RGB10_A2:
-         case GL_RGB5_A1:
-            break;
-         default:
-            return GL_INVALID_OPERATION;
-         }
-         break;
-
-      case GL_HALF_FLOAT:
-         if (internalFormat != GL_RGBA16F)
-            return GL_INVALID_OPERATION;
-         break;
+   case GL_RGBA2:
+   case GL_RGBA4:
+   case GL_RGB5_A1:
+   case GL_RGBA8:
+   case GL_RGB10_A2:
+   case GL_RGBA12:
+   case GL_RGBA16:
+      return GL_RGBA;
+   default:
+      ; /* fallthrough */
+   }
 
-      case GL_FLOAT:
-         switch (internalFormat) {
-         case GL_RGBA16F:
-         case GL_RGBA32F:
-            break;
-         case GL_RGBA:
-            if (ctx->Extensions.OES_texture_float && internalFormat == format)
-               break;
-         default:
-            return GL_INVALID_OPERATION;
-         }
-         break;
+   /* GL_BGRA can be an internal format *only* in OpenGL ES (1.x or 2.0).
+    */
+   if (_mesa_is_gles(ctx)) {
+      switch (internalFormat) {
+      case GL_BGRA:
+         return GL_RGBA;
+      default:
+         ; /* fallthrough */
+      }
+   }
 
-      case GL_HALF_FLOAT_OES:
-         if (ctx->Extensions.OES_texture_half_float && internalFormat == format)
-            break;
+   if (_mesa_has_ARB_ES2_compatibility(ctx) ||
+       _mesa_has_OES_framebuffer_object(ctx) ||
+       ctx->API == API_OPENGLES2) {
+      switch (internalFormat) {
+      case GL_RGB565:
+         return GL_RGB;
       default:
-         return GL_INVALID_OPERATION;
+         ; /* fallthrough */
       }
-      break;
+   }
+
+   if (_mesa_has_ARB_depth_texture(ctx) || _mesa_has_OES_depth_texture(ctx) ||
+       ctx->API == API_OPENGL_CORE) {
+      switch (internalFormat) {
+      case GL_DEPTH_COMPONENT:
+      case GL_DEPTH_COMPONENT16:
+      case GL_DEPTH_COMPONENT24:
+      case GL_DEPTH_COMPONENT32:
+         return GL_DEPTH_COMPONENT;
+      case GL_DEPTH_STENCIL:
+      case GL_DEPTH24_STENCIL8:
+         return GL_DEPTH_STENCIL;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_ARB_texture_stencil8(ctx) ||
+       _mesa_has_OES_texture_stencil8(ctx)) {
+      switch (internalFormat) {
+      case GL_STENCIL_INDEX:
+      case GL_STENCIL_INDEX1:
+      case GL_STENCIL_INDEX4:
+      case GL_STENCIL_INDEX8:
+      case GL_STENCIL_INDEX16:
+         return GL_STENCIL_INDEX;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   switch (internalFormat) {
+   case GL_COMPRESSED_ALPHA:
+      return GL_ALPHA;
+   case GL_COMPRESSED_LUMINANCE:
+      return GL_LUMINANCE;
+   case GL_COMPRESSED_LUMINANCE_ALPHA:
+      return GL_LUMINANCE_ALPHA;
+   case GL_COMPRESSED_INTENSITY:
+      return GL_INTENSITY;
+   case GL_COMPRESSED_RGB:
+      return GL_RGB;
+   case GL_COMPRESSED_RGBA:
+      return GL_RGBA;
+   default:
+      ; /* fallthrough */
+   }
+
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
+      GLenum base_compressed =
+         _mesa_gl_compressed_format_base_format(internalFormat);
+      if (base_compressed)
+            return base_compressed;
+   }
+
+   if ((_mesa_has_KHR_texture_compression_astc_ldr(ctx) &&
+        is_astc_2d_format(internalFormat)) ||
+       (_mesa_has_OES_texture_compression_astc(ctx) &&
+        is_astc_3d_format(internalFormat)))
+        return GL_RGBA;
+
+   if (_mesa_has_MESA_ycbcr_texture(ctx)) {
+      if (internalFormat == GL_YCBCR_MESA)
+         return GL_YCBCR_MESA;
+   }
+
+   if (_mesa_has_half_float_textures(ctx)) {
+      switch (internalFormat) {
+      case GL_ALPHA16F_ARB:
+         return GL_ALPHA;
+      case GL_RGBA16F_ARB:
+         return GL_RGBA;
+      case GL_RGB16F_ARB:
+         return GL_RGB;
+      case GL_INTENSITY16F_ARB:
+         return GL_INTENSITY;
+      case GL_LUMINANCE16F_ARB:
+         return GL_LUMINANCE;
+      case GL_LUMINANCE_ALPHA16F_ARB:
+         return GL_LUMINANCE_ALPHA;
+      }
+   }
+
+   if (_mesa_has_float_textures(ctx)) {
+      switch (internalFormat) {
+      case GL_ALPHA32F_ARB:
+         return GL_ALPHA;
+      case GL_RGBA32F_ARB:
+         return GL_RGBA;
+      case GL_RGB32F_ARB:
+         return GL_RGB;
+      case GL_INTENSITY32F_ARB:
+         return GL_INTENSITY;
+      case GL_LUMINANCE32F_ARB:
+         return GL_LUMINANCE;
+      case GL_LUMINANCE_ALPHA32F_ARB:
+         return GL_LUMINANCE_ALPHA;
+      }
+   }
+
+   if (_mesa_has_EXT_texture_snorm(ctx) || _mesa_is_gles3(ctx)) {
+      switch (internalFormat) {
+      case GL_RED_SNORM:
+      case GL_R8_SNORM:
+      case GL_R16_SNORM:
+         return GL_RED;
+      case GL_RG_SNORM:
+      case GL_RG8_SNORM:
+      case GL_RG16_SNORM:
+         return GL_RG;
+      case GL_RGB_SNORM:
+      case GL_RGB8_SNORM:
+      case GL_RGB16_SNORM:
+         return GL_RGB;
+      case GL_RGBA_SNORM:
+      case GL_RGBA8_SNORM:
+      case GL_RGBA16_SNORM:
+         return GL_RGBA;
+      case GL_ALPHA_SNORM:
+      case GL_ALPHA8_SNORM:
+      case GL_ALPHA16_SNORM:
+         return GL_ALPHA;
+      case GL_LUMINANCE_SNORM:
+      case GL_LUMINANCE8_SNORM:
+      case GL_LUMINANCE16_SNORM:
+         return GL_LUMINANCE;
+      case GL_LUMINANCE_ALPHA_SNORM:
+      case GL_LUMINANCE8_ALPHA8_SNORM:
+      case GL_LUMINANCE16_ALPHA16_SNORM:
+         return GL_LUMINANCE_ALPHA;
+      case GL_INTENSITY_SNORM:
+      case GL_INTENSITY8_SNORM:
+      case GL_INTENSITY16_SNORM:
+         return GL_INTENSITY;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_EXT_texture_sRGB(ctx) || _mesa_is_gles3(ctx)) {
+      switch (internalFormat) {
+      case GL_SRGB_EXT:
+      case GL_SRGB8_EXT:
+      case GL_COMPRESSED_SRGB_EXT:
+         return GL_RGB;
+      case GL_SRGB_ALPHA_EXT:
+      case GL_SRGB8_ALPHA8_EXT:
+      case GL_COMPRESSED_SRGB_ALPHA_EXT:
+         return GL_RGBA;
+      case GL_SLUMINANCE_ALPHA_EXT:
+      case GL_SLUMINANCE8_ALPHA8_EXT:
+      case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
+         return GL_LUMINANCE_ALPHA;
+      case GL_SLUMINANCE_EXT:
+      case GL_SLUMINANCE8_EXT:
+      case GL_COMPRESSED_SLUMINANCE_EXT:
+         return GL_LUMINANCE;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_EXT_texture_sRGB_R8(ctx)) {
+      switch (internalFormat) {
+      case GL_SR8_EXT:
+         return GL_RED;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_integer_textures(ctx)) {
+      switch (internalFormat) {
+      case GL_RGBA8UI_EXT:
+      case GL_RGBA16UI_EXT:
+      case GL_RGBA32UI_EXT:
+      case GL_RGBA8I_EXT:
+      case GL_RGBA16I_EXT:
+      case GL_RGBA32I_EXT:
+         return GL_RGBA;
+      case GL_RGB8UI_EXT:
+      case GL_RGB16UI_EXT:
+      case GL_RGB32UI_EXT:
+      case GL_RGB8I_EXT:
+      case GL_RGB16I_EXT:
+      case GL_RGB32I_EXT:
+         return GL_RGB;
+      }
+   }
+
+   if (_mesa_has_texture_rgb10_a2ui(ctx)) {
+      switch (internalFormat) {
+      case GL_RGB10_A2UI:
+         return GL_RGBA;
+      }
+   }
+
+   if (_mesa_has_integer_textures(ctx)) {
+      switch (internalFormat) {
+      case GL_ALPHA8UI_EXT:
+      case GL_ALPHA16UI_EXT:
+      case GL_ALPHA32UI_EXT:
+      case GL_ALPHA8I_EXT:
+      case GL_ALPHA16I_EXT:
+      case GL_ALPHA32I_EXT:
+         return GL_ALPHA;
+      case GL_INTENSITY8UI_EXT:
+      case GL_INTENSITY16UI_EXT:
+      case GL_INTENSITY32UI_EXT:
+      case GL_INTENSITY8I_EXT:
+      case GL_INTENSITY16I_EXT:
+      case GL_INTENSITY32I_EXT:
+         return GL_INTENSITY;
+      case GL_LUMINANCE8UI_EXT:
+      case GL_LUMINANCE16UI_EXT:
+      case GL_LUMINANCE32UI_EXT:
+      case GL_LUMINANCE8I_EXT:
+      case GL_LUMINANCE16I_EXT:
+      case GL_LUMINANCE32I_EXT:
+         return GL_LUMINANCE;
+      case GL_LUMINANCE_ALPHA8UI_EXT:
+      case GL_LUMINANCE_ALPHA16UI_EXT:
+      case GL_LUMINANCE_ALPHA32UI_EXT:
+      case GL_LUMINANCE_ALPHA8I_EXT:
+      case GL_LUMINANCE_ALPHA16I_EXT:
+      case GL_LUMINANCE_ALPHA32I_EXT:
+         return GL_LUMINANCE_ALPHA;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_rg_textures(ctx)) {
+      switch (internalFormat) {
+      case GL_R16F:
+         if (!_mesa_has_half_float_textures(ctx))
+            break;
+         return GL_RED;
+      case GL_R32F:
+         if (!_mesa_has_float_textures(ctx))
+            break;
+         return GL_RED;
+      case GL_R8I:
+      case GL_R8UI:
+      case GL_R16I:
+      case GL_R16UI:
+      case GL_R32I:
+      case GL_R32UI:
+         if (!_mesa_has_integer_textures(ctx))
+            break;
+         /* FALLTHROUGH */
+      case GL_R8:
+      case GL_R16:
+      case GL_RED:
+      case GL_COMPRESSED_RED:
+         return GL_RED;
+
+      case GL_RG16F:
+         if (!_mesa_has_half_float_textures(ctx))
+            break;
+         return GL_RG;
+      case GL_RG32F:
+         if (!_mesa_has_float_textures(ctx))
+            break;
+         return GL_RG;
+      case GL_RG8I:
+      case GL_RG8UI:
+      case GL_RG16I:
+      case GL_RG16UI:
+      case GL_RG32I:
+      case GL_RG32UI:
+         if (!_mesa_has_integer_textures(ctx))
+            break;
+         /* FALLTHROUGH */
+      case GL_RG:
+      case GL_RG8:
+      case GL_RG16:
+      case GL_COMPRESSED_RG:
+         return GL_RG;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_texture_shared_exponent(ctx)) {
+      switch (internalFormat) {
+      case GL_RGB9_E5_EXT:
+         return GL_RGB;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_packed_float(ctx)) {
+      switch (internalFormat) {
+      case GL_R11F_G11F_B10F_EXT:
+         return GL_RGB;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_has_float_depth_buffer(ctx)) {
+      switch (internalFormat) {
+      case GL_DEPTH_COMPONENT32F:
+         return GL_DEPTH_COMPONENT;
+      case GL_DEPTH32F_STENCIL8:
+         return GL_DEPTH_STENCIL;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   return -1; /* error */
+}
+
+/**
+ * Returns the effective internal format from a texture format and type.
+ * This is used by texture image operations internally for validation, when
+ * the specified internal format is a base (unsized) format.
+ *
+ * This method will only return a valid effective internal format if the
+ * combination of format, type and internal format in base form, is acceptable.
+ *
+ * If a single sized internal format is defined in the spec (OpenGL-ES 3.0.4) or
+ * in extensions, to unambiguously correspond to the given base format, then
+ * that internal format is returned as the effective. Otherwise, if the
+ * combination is accepted but a single effective format is not defined, the
+ * passed base format will be returned instead.
+ *
+ * \param format the texture format
+ * \param type the texture type
+ */
+static GLenum
+gles_effective_internal_format_for_format_and_type(GLenum format,
+                                                   GLenum type)
+{
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      switch (format) {
+      case GL_RGBA:
+         return GL_RGBA8;
+      case GL_RGB:
+         return GL_RGB8;
+      case GL_RG:
+         return GL_RG8;
+      case GL_RED:
+         return GL_R8;
+      /* Although LUMINANCE_ALPHA, LUMINANCE and ALPHA appear in table 3.12,
+       * (section 3.8 Texturing, page 128 of the OpenGL-ES 3.0.4) as effective
+       * internal formats, they do not correspond to GL constants, so the base
+       * format is returned instead.
+       */
+      case GL_BGRA_EXT:
+      case GL_LUMINANCE_ALPHA:
+      case GL_LUMINANCE:
+      case GL_ALPHA:
+         return format;
+      }
+      break;
+
+   case GL_UNSIGNED_SHORT_4_4_4_4:
+      if (format == GL_RGBA)
+         return GL_RGBA4;
+      break;
+
+   case GL_UNSIGNED_SHORT_5_5_5_1:
+      if (format == GL_RGBA)
+         return GL_RGB5_A1;
+      break;
+
+   case GL_UNSIGNED_SHORT_5_6_5:
+      if (format == GL_RGB)
+         return GL_RGB565;
+      break;
+
+   /* OES_packed_depth_stencil */
+   case GL_UNSIGNED_INT_24_8:
+      if (format == GL_DEPTH_STENCIL)
+         return GL_DEPTH24_STENCIL8;
+      break;
+
+   case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+      if (format == GL_DEPTH_STENCIL)
+         return GL_DEPTH32F_STENCIL8;
+      break;
+
+   case GL_UNSIGNED_SHORT:
+      if (format == GL_DEPTH_COMPONENT)
+         return GL_DEPTH_COMPONENT16;
+      break;
+
+   case GL_UNSIGNED_INT:
+      /* It can be DEPTH_COMPONENT16 or DEPTH_COMPONENT24, so just return
+       * the format.
+       */
+      if (format == GL_DEPTH_COMPONENT)
+         return format;
+      break;
+
+   /* OES_texture_float and OES_texture_half_float */
+   case GL_FLOAT:
+      if (format == GL_DEPTH_COMPONENT)
+         return GL_DEPTH_COMPONENT32F;
+      /* fall through */
+   case GL_HALF_FLOAT_OES:
+      switch (format) {
+      case GL_RGBA:
+      case GL_RGB:
+      case GL_LUMINANCE_ALPHA:
+      case GL_LUMINANCE:
+      case GL_ALPHA:
+      case GL_RED:
+      case GL_RG:
+         return format;
+      }
+      break;
+   case GL_HALF_FLOAT:
+      switch (format) {
+      case GL_RG:
+      case GL_RED:
+         return format;
+      }
+      break;
+
+   /* GL_EXT_texture_type_2_10_10_10_REV */
+   case GL_UNSIGNED_INT_2_10_10_10_REV:
+      switch (format) {
+      case GL_RGBA:
+      case GL_RGB:
+         return format;
+      }
+      break;
+
+   default:
+      /* fall through and return NONE */
+      break;
+   }
+
+   return GL_NONE;
+}
+
+/**
+ * Do error checking of format/type combinations for OpenGL ES 3
+ * glTex[Sub]Image, or ES1/ES2 with GL_OES_required_internalformat.
+ * \return error code, or GL_NO_ERROR.
+ */
+GLenum
+_mesa_gles_error_check_format_and_type(const struct gl_context *ctx,
+                                       GLenum format, GLenum type,
+                                       GLenum internalFormat)
+{
+   /* If internalFormat is an unsized format, then the effective internal
+    * format derived from format and type should be used instead. Page 127,
+    * section "3.8 Texturing" of the GLES 3.0.4 spec states:
+    *
+    *    "if internalformat is a base internal format, the effective
+    *     internal format is a sized internal format that is derived
+    *     from the format and type for internal use by the GL.
+    *     Table 3.12 specifies the mapping of format and type to effective
+    *     internal formats. The effective internal format is used by the GL
+    *     for purposes such as texture completeness or type checks for
+    *     CopyTex* commands. In these cases, the GL is required to operate
+    *     as if the effective internal format was used as the internalformat
+    *     when specifying the texture data."
+    */
+   if (_mesa_is_enum_format_unsized(internalFormat)) {
+      GLenum effectiveInternalFormat =
+         gles_effective_internal_format_for_format_and_type(format, type);
+
+      if (effectiveInternalFormat == GL_NONE)
+         return GL_INVALID_OPERATION;
+
+      GLenum baseInternalFormat;
+      if (internalFormat == GL_BGRA_EXT) {
+         /* Unfortunately, _mesa_base_tex_format returns a base format of
+          * GL_RGBA for GL_BGRA_EXT.  This makes perfect sense if you're
+          * asking the question, "what channels does this format have?"
+          * However, if we're trying to determine if two internal formats
+          * match in the ES3 sense, we actually want GL_BGRA.
+          */
+         baseInternalFormat = GL_BGRA_EXT;
+      } else {
+         baseInternalFormat =
+            _mesa_base_tex_format(ctx, effectiveInternalFormat);
+      }
+
+      if (internalFormat != baseInternalFormat)
+         return GL_INVALID_OPERATION;
+
+      internalFormat = effectiveInternalFormat;
+   }
+
+   /* The GLES variant of EXT_texture_compression_s3tc is very vague and
+    * doesn't list valid types. Just do exactly what the spec says.
+    */
+   if (_mesa_has_EXT_texture_compression_s3tc(ctx) &&
+       (internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+        internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+        internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
+        internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT))
+      return format == GL_RGB || format == GL_RGBA ? GL_NO_ERROR :
+                                                     GL_INVALID_OPERATION;
+
+   switch (format) {
+   case GL_BGRA_EXT:
+      if (type != GL_UNSIGNED_BYTE || internalFormat != GL_BGRA)
+         return GL_INVALID_OPERATION;
+      break;
+
+   case GL_RGBA:
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+         switch (internalFormat) {
+         case GL_RGBA:
+         case GL_RGBA8:
+         case GL_RGB5_A1:
+         case GL_RGBA4:
+            break;
+         case GL_SRGB8_ALPHA8_EXT:
+            if (ctx->Version <= 20)
+               return GL_INVALID_OPERATION;
+            break;
+         case GL_COMPRESSED_RGBA_BPTC_UNORM:
+         case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
+            if (!_mesa_has_EXT_texture_compression_bptc(ctx))
+               return GL_INVALID_OPERATION;
+            break;
+         default:
+            return GL_INVALID_OPERATION;
+         }
+         break;
+
+      case GL_BYTE:
+         if (ctx->Version <= 20 || internalFormat != GL_RGBA8_SNORM)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_UNSIGNED_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) || internalFormat != GL_RGBA16)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) ||
+             internalFormat != GL_RGBA16_SNORM)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+         switch (internalFormat) {
+         case GL_RGBA:
+         case GL_RGBA4:
+            break;
+         default:
+            return GL_INVALID_OPERATION;
+         }
+         break;
+
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+         switch (internalFormat) {
+         case GL_RGBA:
+         case GL_RGB5_A1:
+            break;
+         default:
+            return GL_INVALID_OPERATION;
+         }
+         break;
+
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+         switch (internalFormat) {
+         case GL_RGBA:
+         case GL_RGB10_A2:
+         case GL_RGB5_A1:
+            if (!_mesa_has_texture_type_2_10_10_10_REV(ctx))
+               return GL_INVALID_OPERATION;
+            break;
+         default:
+            return GL_INVALID_OPERATION;
+         }
+         break;
+
+      case GL_HALF_FLOAT:
+         if (ctx->Version <= 20 || internalFormat != GL_RGBA16F)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_FLOAT:
+         switch (internalFormat) {
+         case GL_RGBA16F:
+         case GL_RGBA32F:
+            if (ctx->Version <= 20)
+               return GL_INVALID_OPERATION;
+            break;
+         case GL_RGBA:
+            if (!_mesa_has_OES_texture_float(ctx) || internalFormat != format)
+               return GL_INVALID_OPERATION;
+            break;
+         default:
+            return GL_INVALID_OPERATION;
+         }
+         break;
+
+      case GL_HALF_FLOAT_OES:
+         if (!_mesa_has_OES_texture_half_float(ctx) || internalFormat != format)
+            return GL_INVALID_OPERATION;
+         break;
+      default:
+         return GL_INVALID_OPERATION;
+      }
+      break;
 
    case GL_RGBA_INTEGER:
+      if (ctx->Version <= 20)
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
          if (internalFormat != GL_RGBA8UI)
@@ -2169,7 +2994,10 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          case GL_RGB:
          case GL_RGB8:
          case GL_RGB565:
+            break;
          case GL_SRGB8:
+            if (ctx->Version <= 20)
+               return GL_INVALID_OPERATION;
             break;
          default:
             return GL_INVALID_OPERATION;
@@ -2177,7 +3005,18 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          break;
 
       case GL_BYTE:
-         if (internalFormat != GL_RGB8_SNORM)
+         if (ctx->Version <= 20 || internalFormat != GL_RGB8_SNORM)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_UNSIGNED_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) || internalFormat != GL_RGB16)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) ||
+             internalFormat != GL_RGB16_SNORM)
             return GL_INVALID_OPERATION;
          break;
 
@@ -2192,16 +3031,18 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          break;
 
       case GL_UNSIGNED_INT_10F_11F_11F_REV:
-         if (internalFormat != GL_R11F_G11F_B10F)
+         if (ctx->Version <= 20 || internalFormat != GL_R11F_G11F_B10F)
             return GL_INVALID_OPERATION;
          break;
 
       case GL_UNSIGNED_INT_5_9_9_9_REV:
-         if (internalFormat != GL_RGB9_E5)
+         if (ctx->Version <= 20 || internalFormat != GL_RGB9_E5)
             return GL_INVALID_OPERATION;
          break;
 
       case GL_HALF_FLOAT:
+         if (ctx->Version <= 20)
+            return GL_INVALID_OPERATION;
          switch (internalFormat) {
          case GL_RGB16F:
          case GL_R11F_G11F_B10F:
@@ -2218,23 +3059,40 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          case GL_RGB32F:
          case GL_R11F_G11F_B10F:
          case GL_RGB9_E5:
+            if (ctx->Version <= 20)
+               return GL_INVALID_OPERATION;
+            break;
+         case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
+         case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
+            if (!_mesa_has_EXT_texture_compression_bptc(ctx))
+               return GL_INVALID_OPERATION;
             break;
          case GL_RGB:
-            if (ctx->Extensions.OES_texture_float && internalFormat == format)
-               break;
+            if (!_mesa_has_OES_texture_float(ctx) || internalFormat != format)
+               return GL_INVALID_OPERATION;
+            break;
          default:
             return GL_INVALID_OPERATION;
          }
          break;
 
       case GL_HALF_FLOAT_OES:
-         if (!ctx->Extensions.OES_texture_half_float || internalFormat != format)
+         if (!_mesa_has_OES_texture_half_float(ctx) || internalFormat != format)
             return GL_INVALID_OPERATION;
          break;
 
       case GL_UNSIGNED_INT_2_10_10_10_REV:
          switch (internalFormat) {
-         case GL_RGB: /* GL_EXT_texture_type_2_10_10_10_REV */
+         case GL_RGB:
+         case GL_RGB10:
+         case GL_RGB8:
+         case GL_RGB565:
+            /* GL_EXT_texture_type_2_10_10_10_REV allows GL_RGB even though
+             * GLES3 doesn't, and GL_OES_required_internalformat extends that
+             * to allow the sized RGB internalformats as well.
+             */
+            if (!_mesa_has_texture_type_2_10_10_10_REV(ctx))
+               return GL_INVALID_OPERATION;
             break;
          default:
             return GL_INVALID_OPERATION;
@@ -2247,6 +3105,8 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       break;
 
    case GL_RGB_INTEGER:
+      if (ctx->Version <= 20)
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
          if (internalFormat != GL_RGB8UI)
@@ -2284,27 +3144,61 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       break;
 
    case GL_RG:
+      if (!_mesa_has_rg_textures(ctx))
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
-         if (internalFormat != GL_RG8)
+         if (internalFormat != GL_RG8 &&
+             (!_mesa_has_EXT_texture_compression_rgtc(ctx) ||
+              internalFormat != GL_COMPRESSED_RED_GREEN_RGTC2_EXT))
             return GL_INVALID_OPERATION;
          break;
 
       case GL_BYTE:
-         if (internalFormat != GL_RG8_SNORM)
+         if (internalFormat != GL_RG8_SNORM &&
+             (!_mesa_has_EXT_texture_compression_rgtc(ctx) ||
+              internalFormat != GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT))
             return GL_INVALID_OPERATION;
          break;
 
-      case GL_HALF_FLOAT:
-         if (internalFormat != GL_RG16F)
+      case GL_UNSIGNED_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) || internalFormat != GL_RG16)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) ||
+             internalFormat != GL_RG16_SNORM)
             return GL_INVALID_OPERATION;
          break;
 
+      case GL_HALF_FLOAT:
+      case GL_HALF_FLOAT_OES:
+         switch (internalFormat) {
+            case GL_RG16F:
+               if (ctx->Version <= 20)
+                  return GL_INVALID_OPERATION;
+               break;
+            case GL_RG:
+               if (!_mesa_has_rg_textures(ctx) ||
+                   !_mesa_has_OES_texture_half_float(ctx))
+                  return GL_INVALID_OPERATION;
+               break;
+            default:
+               return GL_INVALID_OPERATION;
+         }
+         break;
+
       case GL_FLOAT:
          switch (internalFormat) {
          case GL_RG16F:
          case GL_RG32F:
             break;
+         case GL_RG:
+            if (!_mesa_has_rg_textures(ctx) ||
+                !_mesa_has_OES_texture_float(ctx))
+               return GL_INVALID_OPERATION;
+            break;
          default:
             return GL_INVALID_OPERATION;
          }
@@ -2316,6 +3210,8 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       break;
 
    case GL_RG_INTEGER:
+      if (ctx->Version <= 20)
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
          if (internalFormat != GL_RG8UI)
@@ -2353,20 +3249,52 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       break;
 
    case GL_RED:
+      if (!_mesa_has_rg_textures(ctx))
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
-         if (internalFormat != GL_R8)
+         if (internalFormat == GL_R8 ||
+             ((internalFormat == GL_SR8_EXT) &&
+              _mesa_has_EXT_texture_sRGB_R8(ctx)) ||
+             (internalFormat == GL_COMPRESSED_RED_RGTC1_EXT &&
+              _mesa_has_EXT_texture_compression_rgtc(ctx)))
+            break;
+         return GL_INVALID_OPERATION;
+
+      case GL_BYTE:
+         if (internalFormat != GL_R8_SNORM &&
+             (!_mesa_has_EXT_texture_compression_rgtc(ctx) ||
+              internalFormat != GL_COMPRESSED_SIGNED_RED_RGTC1_EXT))
             return GL_INVALID_OPERATION;
          break;
 
-      case GL_BYTE:
-         if (internalFormat != GL_R8_SNORM)
+      case GL_UNSIGNED_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) || internalFormat != GL_R16)
+            return GL_INVALID_OPERATION;
+         break;
+
+      case GL_SHORT:
+         if (!_mesa_has_EXT_texture_norm16(ctx) ||
+             internalFormat != GL_R16_SNORM)
             return GL_INVALID_OPERATION;
          break;
 
       case GL_HALF_FLOAT:
-         if (internalFormat != GL_R16F)
+      case GL_HALF_FLOAT_OES:
+         switch (internalFormat) {
+         case GL_R16F:
+            if (ctx->Version <= 20)
+               return GL_INVALID_OPERATION;
+            break;
+         case GL_RG:
+         case GL_RED:
+            if (!_mesa_has_rg_textures(ctx) ||
+                !_mesa_has_OES_texture_half_float(ctx))
+               return GL_INVALID_OPERATION;
+            break;
+         default:
             return GL_INVALID_OPERATION;
+         }
          break;
 
       case GL_FLOAT:
@@ -2374,6 +3302,11 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          case GL_R16F:
          case GL_R32F:
             break;
+         case GL_RED:
+            if (!_mesa_has_rg_textures(ctx) ||
+                !_mesa_has_OES_texture_float(ctx))
+               return GL_INVALID_OPERATION;
+            break;
          default:
             return GL_INVALID_OPERATION;
          }
@@ -2385,6 +3318,8 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       break;
 
    case GL_RED_INTEGER:
+      if (ctx->Version <= 20)
+         return GL_INVALID_OPERATION;
       switch (type) {
       case GL_UNSIGNED_BYTE:
          if (internalFormat != GL_R8UI)
@@ -2441,7 +3376,7 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          break;
 
       case GL_FLOAT:
-         if (internalFormat != GL_DEPTH_COMPONENT32F)
+         if (ctx->Version <= 20 || internalFormat != GL_DEPTH_COMPONENT32F)
             return GL_INVALID_OPERATION;
          break;
 
@@ -2459,7 +3394,7 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
          break;
 
       case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-         if (internalFormat != GL_DEPTH32F_STENCIL8)
+         if (ctx->Version <= 20 || internalFormat != GL_DEPTH32F_STENCIL8)
             return GL_INVALID_OPERATION;
          break;
 
@@ -2468,20 +3403,40 @@ _mesa_es3_error_check_format_and_type(const struct gl_context *ctx,
       }
       break;
 
+   case GL_STENCIL_INDEX:
+      if (!_mesa_has_OES_texture_stencil8(ctx) ||
+          type != GL_UNSIGNED_BYTE ||
+          internalFormat != GL_STENCIL_INDEX8) {
+         return GL_INVALID_OPERATION;
+      }
+      break;
+
    case GL_ALPHA:
    case GL_LUMINANCE:
    case GL_LUMINANCE_ALPHA:
       switch (type) {
       case GL_FLOAT:
-         if (ctx->Extensions.OES_texture_float && internalFormat == format)
-            break;
+         if (!_mesa_has_OES_texture_float(ctx) || internalFormat != format)
+            return GL_INVALID_OPERATION;
+         break;
       case GL_HALF_FLOAT_OES:
-         if (ctx->Extensions.OES_texture_half_float && internalFormat == format)
-            break;
-      default:
-         if (type != GL_UNSIGNED_BYTE || format != internalFormat)
+         if (!_mesa_has_OES_texture_half_float(ctx) || internalFormat != format)
+            return GL_INVALID_OPERATION;
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (!(format == internalFormat ||
+               (format == GL_ALPHA && internalFormat == GL_ALPHA8) ||
+               (format == GL_LUMINANCE && internalFormat == GL_LUMINANCE8) ||
+               (format == GL_LUMINANCE_ALPHA &&
+                ((internalFormat == GL_LUMINANCE8_ALPHA8) ||
+                 (internalFormat == GL_LUMINANCE4_ALPHA4))))) {
             return GL_INVALID_OPERATION;
+         }
+         break;
+      default:
+         return GL_INVALID_OPERATION;
       }
+      break;
    }
 
    return GL_NO_ERROR;
@@ -2550,7 +3505,43 @@ get_swizzle_from_gl_format(GLenum format, uint8_t *swizzle)
    case GL_INTENSITY:
       set_swizzle(swizzle, 0, 0, 0, 0);
       return true;
+   case GL_DEPTH_COMPONENT:
+      set_swizzle(swizzle, 0, 6, 6, 6);
+      return true;
+   case GL_STENCIL_INDEX:
+      set_swizzle(swizzle, 6, 0, 6, 6);
+      return true;
+   default:
+      return false;
+   }
+}
+
+bool
+_mesa_swap_bytes_in_type_enum(GLenum *type)
+{
+   switch (*type) {
+   case GL_UNSIGNED_INT_8_8_8_8:
+      *type = GL_UNSIGNED_INT_8_8_8_8_REV;
+      return true;
+   case GL_UNSIGNED_INT_8_8_8_8_REV:
+      *type = GL_UNSIGNED_INT_8_8_8_8;
+      return true;
+   case GL_UNSIGNED_SHORT_8_8_MESA:
+      *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
+      return true;
+   case GL_UNSIGNED_SHORT_8_8_REV_MESA:
+      *type = GL_UNSIGNED_SHORT_8_8_MESA;
+      return true;
+   case GL_BYTE:
+   case GL_UNSIGNED_BYTE:
+      /* format/types that are arrays of 8-bit values are unaffected by
+       * swapBytes.
+       */
+      return true;
    default:
+      /* swapping bytes on 4444, 1555, or >8 bit per channel types etc. will
+       * never match a Mesa format.
+       */
       return false;
    }
 }
@@ -2574,13 +3565,14 @@ get_swizzle_from_gl_format(GLenum format, uint8_t *swizzle)
 uint32_t
 _mesa_format_from_format_and_type(GLenum format, GLenum type)
 {
-   mesa_array_format array_format;
-
    bool is_array_format = true;
    uint8_t swizzle[4];
    bool normalized = false, is_float = false, is_signed = false;
    int num_channels = 0, type_size = 0;
 
+   if (format == GL_COLOR_INDEX)
+      return MESA_FORMAT_NONE;
+
    /* Extract array format type information from the OpenGL data type */
    switch (type) {
    case GL_UNSIGNED_BYTE:
@@ -2628,18 +3620,26 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
     * create the array format
     */
    if (is_array_format) {
-      normalized = !_mesa_is_enum_format_integer(format);
-      num_channels = _mesa_components_in_format(format);
-
-      array_format =
-         MESA_ARRAY_FORMAT(type_size, is_signed, is_float,
-                           normalized, num_channels,
-                           swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
+      enum mesa_array_format_base_format bf;
+      switch (format) {
+      case GL_DEPTH_COMPONENT:
+         bf = MESA_ARRAY_FORMAT_BASE_FORMAT_DEPTH;
+         break;
+      case GL_STENCIL_INDEX:
+         bf = MESA_ARRAY_FORMAT_BASE_FORMAT_STENCIL;
+         break;
+      default:
+         bf = MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS;
+         break;
+      }
 
-      if (!_mesa_little_endian())
-         array_format = _mesa_array_format_flip_channels(array_format);
+      normalized = !(_mesa_is_enum_format_integer(format) ||
+                     format == GL_STENCIL_INDEX);
+      num_channels = _mesa_components_in_format(format);
 
-      return array_format;
+      return MESA_ARRAY_FORMAT(bf, type_size, is_signed, is_float,
+                               normalized, num_channels,
+                               swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
    }
 
    /* Otherwise this is not an array format, so return the mesa_format
@@ -2651,12 +3651,16 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
          return MESA_FORMAT_B5G6R5_UNORM;
       else if (format == GL_BGR)
          return MESA_FORMAT_R5G6B5_UNORM;
+      else if (format == GL_RGB_INTEGER)
+         return MESA_FORMAT_B5G6R5_UINT;
       break;
    case GL_UNSIGNED_SHORT_5_6_5_REV:
       if (format == GL_RGB)
          return MESA_FORMAT_R5G6B5_UNORM;
       else if (format == GL_BGR)
          return MESA_FORMAT_B5G6R5_UNORM;
+      else if (format == GL_RGB_INTEGER)
+         return MESA_FORMAT_R5G6B5_UINT;
       break;
    case GL_UNSIGNED_SHORT_4_4_4_4:
       if (format == GL_RGBA)
@@ -2665,6 +3669,10 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
          return MESA_FORMAT_A4R4G4B4_UNORM;
       else if (format == GL_ABGR_EXT)
          return MESA_FORMAT_R4G4B4A4_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_A4B4G4R4_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_A4R4G4B4_UINT;
       break;
    case GL_UNSIGNED_SHORT_4_4_4_4_REV:
       if (format == GL_RGBA)
@@ -2673,26 +3681,42 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
          return MESA_FORMAT_B4G4R4A4_UNORM;
       else if (format == GL_ABGR_EXT)
          return MESA_FORMAT_A4B4G4R4_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_R4G4B4A4_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_B4G4R4A4_UINT;
       break;
    case GL_UNSIGNED_SHORT_5_5_5_1:
       if (format == GL_RGBA)
          return MESA_FORMAT_A1B5G5R5_UNORM;
       else if (format == GL_BGRA)
          return MESA_FORMAT_A1R5G5B5_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_A1B5G5R5_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_A1R5G5B5_UINT;
       break;
    case GL_UNSIGNED_SHORT_1_5_5_5_REV:
       if (format == GL_RGBA)
          return MESA_FORMAT_R5G5B5A1_UNORM;
       else if (format == GL_BGRA)
          return MESA_FORMAT_B5G5R5A1_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_R5G5B5A1_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_B5G5R5A1_UINT;
       break;
    case GL_UNSIGNED_BYTE_3_3_2:
       if (format == GL_RGB)
          return MESA_FORMAT_B2G3R3_UNORM;
+      else if (format == GL_RGB_INTEGER)
+         return MESA_FORMAT_B2G3R3_UINT;
       break;
    case GL_UNSIGNED_BYTE_2_3_3_REV:
       if (format == GL_RGB)
          return MESA_FORMAT_R3G3B2_UNORM;
+      else if (format == GL_RGB_INTEGER)
+         return MESA_FORMAT_R3G3B2_UINT;
       break;
    case GL_UNSIGNED_INT_5_9_9_9_REV:
       if (format == GL_RGB)
@@ -2727,6 +3751,10 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
          return MESA_FORMAT_A8R8G8B8_UNORM;
       else if (format == GL_ABGR_EXT)
          return MESA_FORMAT_R8G8B8A8_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_A8B8G8R8_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_A8R8G8B8_UINT;
       break;
    case GL_UNSIGNED_INT_8_8_8_8_REV:
       if (format == GL_RGBA)
@@ -2735,6 +3763,10 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
          return MESA_FORMAT_B8G8R8A8_UNORM;
       else if (format == GL_ABGR_EXT)
          return MESA_FORMAT_A8B8G8R8_UNORM;
+      else if (format == GL_RGBA_INTEGER)
+         return MESA_FORMAT_R8G8B8A8_UINT;
+      else if (format == GL_BGRA_INTEGER)
+         return MESA_FORMAT_B8G8R8A8_UINT;
       break;
    case GL_UNSIGNED_SHORT_8_8_MESA:
       if (format == GL_YCBCR_MESA)
@@ -2747,13 +3779,176 @@ _mesa_format_from_format_and_type(GLenum format, GLenum type)
    case GL_UNSIGNED_INT_10F_11F_11F_REV:
       if (format == GL_RGB)
          return MESA_FORMAT_R11G11B10_FLOAT;
+      break;
+   case GL_FLOAT:
+      if (format == GL_DEPTH_COMPONENT)
+         return MESA_FORMAT_Z_FLOAT32;
+      break;
+   case GL_UNSIGNED_INT:
+      if (format == GL_DEPTH_COMPONENT)
+         return MESA_FORMAT_Z_UNORM32;
+      break;
+   case GL_UNSIGNED_SHORT:
+      if (format == GL_DEPTH_COMPONENT)
+         return MESA_FORMAT_Z_UNORM16;
+      break;
+   case GL_UNSIGNED_INT_24_8:
+      if (format == GL_DEPTH_STENCIL)
+         return MESA_FORMAT_S8_UINT_Z24_UNORM;
+      else if (format == GL_DEPTH_COMPONENT)
+         return MESA_FORMAT_X8_UINT_Z24_UNORM;
+      break;
+   case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+      if (format == GL_DEPTH_STENCIL)
+         return MESA_FORMAT_Z32_FLOAT_S8X24_UINT;
+      break;
    default:
       break;
    }
 
+   fprintf(stderr, "Unsupported format/type: %s/%s\n",
+           _mesa_enum_to_string(format),
+           _mesa_enum_to_string(type));
+
    /* If we got here it means that we could not find a Mesa format that
     * matches the GL format/type provided. We may need to add a new Mesa
     * format in that case.
     */
    unreachable("Unsupported format");
 }
+
+uint32_t
+_mesa_tex_format_from_format_and_type(const struct gl_context *ctx,
+                                      GLenum gl_format, GLenum type)
+{
+   mesa_format format = _mesa_format_from_format_and_type(gl_format, type);
+
+   if (_mesa_format_is_mesa_array_format(format))
+      format = _mesa_format_from_array_format(format);
+      
+   if (format == MESA_FORMAT_NONE || !ctx->TextureFormatSupported[format])
+      return MESA_FORMAT_NONE;
+
+   return format;
+}
+
+/**
+ * Returns true if \p internal_format is a sized internal format that
+ * is marked "Color Renderable" in Table 8.10 of the ES 3.2 specification.
+ */
+bool
+_mesa_is_es3_color_renderable(const struct gl_context *ctx,
+                              GLenum internal_format)
+{
+   switch (internal_format) {
+   case GL_R8:
+   case GL_RG8:
+   case GL_RGB8:
+   case GL_RGB565:
+   case GL_RGBA4:
+   case GL_RGB5_A1:
+   case GL_RGBA8:
+   case GL_RGB10_A2:
+   case GL_RGB10_A2UI:
+   case GL_SRGB8_ALPHA8:
+   case GL_R16F:
+   case GL_RG16F:
+   case GL_RGBA16F:
+   case GL_R32F:
+   case GL_RG32F:
+   case GL_RGBA32F:
+   case GL_R11F_G11F_B10F:
+   case GL_R8I:
+   case GL_R8UI:
+   case GL_R16I:
+   case GL_R16UI:
+   case GL_R32I:
+   case GL_R32UI:
+   case GL_RG8I:
+   case GL_RG8UI:
+   case GL_RG16I:
+   case GL_RG16UI:
+   case GL_RG32I:
+   case GL_RG32UI:
+   case GL_RGBA8I:
+   case GL_RGBA8UI:
+   case GL_RGBA16I:
+   case GL_RGBA16UI:
+   case GL_RGBA32I:
+   case GL_RGBA32UI:
+      return true;
+   case GL_R16:
+   case GL_RG16:
+   case GL_RGBA16:
+      return _mesa_has_EXT_texture_norm16(ctx);
+   case GL_R8_SNORM:
+   case GL_RG8_SNORM:
+   case GL_RGBA8_SNORM:
+      return _mesa_has_EXT_render_snorm(ctx);
+   case GL_R16_SNORM:
+   case GL_RG16_SNORM:
+   case GL_RGBA16_SNORM:
+      return _mesa_has_EXT_texture_norm16(ctx) &&
+             _mesa_has_EXT_render_snorm(ctx);
+   default:
+      return false;
+   }
+}
+
+/**
+ * Returns true if \p internal_format is a sized internal format that
+ * is marked "Texture Filterable" in Table 8.10 of the ES 3.2 specification.
+ */
+bool
+_mesa_is_es3_texture_filterable(const struct gl_context *ctx,
+                                GLenum internal_format)
+{
+   switch (internal_format) {
+   case GL_R8:
+   case GL_R8_SNORM:
+   case GL_RG8:
+   case GL_RG8_SNORM:
+   case GL_RGB8:
+   case GL_RGB8_SNORM:
+   case GL_RGB565:
+   case GL_RGBA4:
+   case GL_RGB5_A1:
+   case GL_RGBA8:
+   case GL_RGBA8_SNORM:
+   case GL_RGB10_A2:
+   case GL_SRGB8:
+   case GL_SRGB8_ALPHA8:
+   case GL_R16F:
+   case GL_RG16F:
+   case GL_RGB16F:
+   case GL_RGBA16F:
+   case GL_R11F_G11F_B10F:
+   case GL_RGB9_E5:
+      return true;
+   case GL_R16:
+   case GL_R16_SNORM:
+   case GL_RG16:
+   case GL_RG16_SNORM:
+   case GL_RGB16:
+   case GL_RGB16_SNORM:
+   case GL_RGBA16:
+   case GL_RGBA16_SNORM:
+      return _mesa_has_EXT_texture_norm16(ctx);
+   case GL_R32F:
+   case GL_RG32F:
+   case GL_RGB32F:
+   case GL_RGBA32F:
+      /* The OES_texture_float_linear spec says:
+       *
+       *    "When implemented against OpenGL ES 3.0 or later versions, sized
+       *     32-bit floating-point formats become texture-filterable. This
+       *     should be noted by, for example, checking the ``TF'' column of
+       *     table 8.13 in the ES 3.1 Specification (``Correspondence of sized
+       *     internal formats to base internal formats ... and use cases ...'')
+       *     for the R32F, RG32F, RGB32F, and RGBA32F formats."
+       */
+      return _mesa_has_OES_texture_float_linear(ctx);
+   default:
+      return false;
+   }
+}