+// ES3 has a specific set of permutations of internal formats, formats and types which are acceptable.
+struct ES3FormatCombination
+{
+ GLenum internalFormat;
+ GLenum format;
+ GLenum type;
+};
+
+bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b)
+{
+ return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0;
+}
+
+typedef std::set<ES3FormatCombination> ES3FormatCombinationSet;
+
+static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type)
+{
+ ES3FormatCombination info;
+ info.internalFormat = internalFormat;
+ info.format = format;
+ info.type = type;
+ set->insert(info);
+}
+
+ES3FormatCombinationSet BuildES3FormatSet()
+{
+ ES3FormatCombinationSet set;
+
+ // Format combinations from ES 3.0.1 spec, table 3.2
+
+ // | Internal format | Format | Type |
+ // | | | |
+ InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
+ InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
+ InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
+ InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
+ InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT );
+ InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT );
+ InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT );
+ InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV );
+ InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
+ InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV );
+ InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV );
+ InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT );
+ InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT );
+ InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT );
+ InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT );
+ InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT );
+ InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT );
+ InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE );
+ InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT );
+ InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT );
+ InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT );
+
+ // Unsized formats
+ InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
+ InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
+ InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
+
+ // Depth stencil formats
+ InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT );
+ InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
+ InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
+ InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
+
+ // From GL_EXT_sRGB
+ InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
+
+ // From GL_OES_texture_float
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT );
+
+ // From GL_OES_texture_half_float
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES );
+
+ // From GL_EXT_texture_format_BGRA8888
+ InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
+
+ // From GL_EXT_texture_storage
+ // | Internal format | Format | Type |
+ // | | | |
+ InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
+
+ // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
+ InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT);
+ InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT);
+ InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
+
+ // From GL_ANGLE_depth_texture
+ InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
+
+ // Compressed formats
+ // From ES 3.0.1 spec, table 3.16
+ // | Internal format | Format | Type |
+ // | | | |
+ InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE);
+
+
+ // From GL_EXT_texture_compression_dxt1
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
+
+ // From GL_ANGLE_texture_compression_dxt3
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE);
+
+ // From GL_ANGLE_texture_compression_dxt5
+ InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE);
+
+ return set;
+}
+
+static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
+{
+ // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
+ // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+ if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
+ {
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+
+ // The type and format are valid if any supported internal format has that type and format
+ bool formatSupported = false;
+ bool typeSupported = false;
+
+ static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet();
+ for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++)
+ {
+ if (i->format == format || i->type == type)
+ {
+ const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat);
+ bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions());
+ if (supported && i->type == type)
+ {
+ typeSupported = true;
+ }
+ if (supported && i->format == format)
+ {
+ formatSupported = true;
+ }
+
+ // Early-out if both type and format are supported now
+ if (typeSupported && formatSupported)
+ {
+ break;
+ }
+ }
+ }
+
+ if (!typeSupported || !formatSupported)
+ {
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+
+ // Check if this is a valid format combination to load texture data
+ ES3FormatCombination searchFormat;
+ searchFormat.internalFormat = internalFormat;
+ searchFormat.format = format;
+ searchFormat.type = type;
+
+ if (es3FormatSet.find(searchFormat) == es3FormatSet.end())
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ return true;
+}
+