+ 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)
+ break;
+ default:
+ return GL_INVALID_OPERATION;
+ }
+ break;
+
+ case GL_HALF_FLOAT_OES:
+ if (_mesa_has_OES_texture_half_float(ctx) && internalFormat == format)
+ 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)
+ return GL_INVALID_OPERATION;
+ break;
+
+ case GL_BYTE:
+ if (internalFormat != GL_RGBA8I)
+ return GL_INVALID_OPERATION;
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ if (internalFormat != GL_RGBA16UI)
+ return GL_INVALID_OPERATION;