Make fbo completeness format rules forward compatible.

- Detect and expose context version as an extension in glsFBOUtil.
- Add rules for GLES2 formats changed in GLES3 but with no GLES2
  extension with same functionality.
- Add rules for GLES3 formats changed in GLES31 but with no GLES31
  extension with same functionality.

Bug: 18800966
Change-Id: I297fa9738d8e51e87ccf84dfde6a13c7fd45c7ce
diff --git a/modules/gles2/functional/es2fFboCompletenessTests.cpp b/modules/gles2/functional/es2fFboCompletenessTests.cpp
index 49c52de..a74abd3 100644
--- a/modules/gles2/functional/es2fFboCompletenessTests.cpp
+++ b/modules/gles2/functional/es2fFboCompletenessTests.cpp
@@ -102,6 +102,38 @@
 	GL_SRGB8_ALPHA8
 };
 
+// DEQP_gles3_core_no_extension_features
+static const FormatKey s_es3NoExtRboFormats[] =
+{
+	GL_RGB10_A2,
+};
+static const FormatKey s_es3NoExtTextureFormats[] =
+{
+	GL_R16F,
+	GL_RG16F,
+	GL_RGB16F,
+	GL_RGBA16F,
+	GL_R11F_G11F_B10F,
+};
+static const FormatKey s_es3NoExtTextureColorRenderableFormats[] =
+{
+	GL_R8,
+	GL_RG8,
+};
+
+// with ES3 core and GL_EXT_color_buffer_float
+static const FormatKey s_es3NoExtExtColorBufferFloatFormats[] =
+{
+	// \note Only the GLES2+exts subset of formats
+	GL_R11F_G11F_B10F, GL_RGBA16F, GL_RG16F, GL_R16F,
+};
+
+// with ES3 core with OES_texture_stencil8
+static const FormatKey s_es3NoExtOesTextureStencil8Formats[] =
+{
+	GL_STENCIL_INDEX8,
+};
+
 static const FormatExtEntry s_es2ExtFormats[] =
 {
 	// The extension does not specify these to be color-renderable.
@@ -122,6 +154,41 @@
 		REQUIRED_RENDERABLE | TEXTURE_VALID | COLOR_RENDERABLE | RENDERBUFFER_VALID,
 		GLS_ARRAY_RANGE(s_extSrgbWriteControlFormats)
 	},
+
+	// Since GLES3 is "backwards compatible" to GLES2, we might actually be running on a GLES3
+	// context. Since GLES3 added some features to core with no corresponding GLES2 extension,
+	// some tests might produce wrong results (since they are using rules of GLES2 & extensions)
+	//
+	// To avoid this, require new features of GLES3 that have no matching GLES2 extension if
+	// context is GLES3. This can be done with a DEQP_* extensions.
+	//
+	// \note Not all feature changes are listed here but only those that alter GLES2 subset of
+	//       the formats
+	{
+		"DEQP_gles3_core_compatible",
+		REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
+		GLS_ARRAY_RANGE(s_es3NoExtRboFormats)
+	},
+	{
+		"DEQP_gles3_core_compatible",
+		TEXTURE_VALID,
+		GLS_ARRAY_RANGE(s_es3NoExtTextureFormats)
+	},
+	{
+		"DEQP_gles3_core_compatible",
+		REQUIRED_RENDERABLE | TEXTURE_VALID | COLOR_RENDERABLE,
+		GLS_ARRAY_RANGE(s_es3NoExtTextureColorRenderableFormats)
+	},
+	{
+		"DEQP_gles3_core_compatible GL_EXT_color_buffer_float",
+		REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
+		GLS_ARRAY_RANGE(s_es3NoExtExtColorBufferFloatFormats)
+	},
+	{
+		"DEQP_gles3_core_compatible GL_OES_texture_stencil8",
+		REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID,
+		GLS_ARRAY_RANGE(s_es3NoExtOesTextureStencil8Formats)
+	},
 };
 
 class ES2Checker : public Checker
diff --git a/modules/gles3/functional/es3fFboCompletenessTests.cpp b/modules/gles3/functional/es3fFboCompletenessTests.cpp
index 858da35..7bfa647 100644
--- a/modules/gles3/functional/es3fFboCompletenessTests.cpp
+++ b/modules/gles3/functional/es3fFboCompletenessTests.cpp
@@ -136,19 +136,39 @@
 	GL_STENCIL_INDEX8,
 };
 
+// GL_EXT_render_snorm
+static const FormatKey s_extRenderSnorm[] =
+{
+	GL_R8_SNORM, GL_RG8_SNORM, GL_RGBA8_SNORM,
+};
 
 static const FormatExtEntry s_es3ExtFormats[] =
 {
-	{ "GL_EXT_color_buffer_float",
-	  // These are already texture-valid in ES3, the extension just adds RBO
-	  // support and makes them color-renderable.
-	  REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
-	  GLS_ARRAY_RANGE(s_extColorBufferFloatFormats) },
-	{ "GL_OES_texture_stencil8",
-	  // Note: es3 RBO tests actually cover the first two requirements
-      // - kept here for completeness
-      REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID,
-	  GLS_ARRAY_RANGE(s_extOESTextureStencil8) }
+	{
+		"GL_EXT_color_buffer_float",
+		// These are already texture-valid in ES3, the extension just adds RBO
+		// support and makes them color-renderable.
+		REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
+		GLS_ARRAY_RANGE(s_extColorBufferFloatFormats)
+	},
+	{
+		"GL_OES_texture_stencil8",
+		// \note: es3 RBO tests actually cover the first two requirements
+		// - kept here for completeness
+		REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID,
+		GLS_ARRAY_RANGE(s_extOESTextureStencil8)
+	},
+
+	// Since GLES31 is backwards compatible to GLES3, we might actually be running on a GLES31.
+	// Add rule changes of GLES31 that have no corresponding GLES3 extension.
+	//
+	// \note Not all feature changes are listed here but only those that alter GLES3 subset of
+	//       the formats
+	{
+		"DEQP_gles31_core_compatible GL_EXT_render_snorm",
+		REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID | RENDERBUFFER_VALID,
+		GLS_ARRAY_RANGE(s_extRenderSnorm)
+	},
 };
 
 class ES3Checker : public Checker
diff --git a/modules/glshared/glsFboCompletenessTests.cpp b/modules/glshared/glsFboCompletenessTests.cpp
index 9627198..5b2a7e7 100644
--- a/modules/glshared/glsFboCompletenessTests.cpp
+++ b/modules/glshared/glsFboCompletenessTests.cpp
@@ -459,12 +459,12 @@
 		extName = *it++;
 		while (it != requiredExtensions.end())
 		{
-			msg << extName;
+			msg << getExtensionDescription(extName);
 			extName = *it++;
 			msg << (it == requiredExtensions.end() ? " and " : ", ");
 		}
 
-		msg << extName << '\n';
+		msg << getExtensionDescription(extName) << '\n';
 	}
 }
 
diff --git a/modules/glshared/glsFboUtil.cpp b/modules/glshared/glsFboUtil.cpp
index 76c1c6d..c18521c 100644
--- a/modules/glshared/glsFboUtil.cpp
+++ b/modules/glshared/glsFboUtil.cpp
@@ -162,6 +162,58 @@
 		   ((requiredExtensions == other.requiredExtensions) && (flags < other.flags));
 }
 
+static bool detectGLESCompatibleContext (const RenderContext& ctx, int requiredMajor, int requiredMinor)
+{
+	const glw::Functions&	gl				= ctx.getFunctions();
+	glw::GLint				majorVersion	= 0;
+	glw::GLint				minorVersion	= 0;
+
+	// Detect compatible GLES context by querying GL_MAJOR_VERSION.
+	// This query does not exist on GLES2 so a failing query implies
+	// GLES2 context.
+
+	gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
+	if (gl.getError() != GL_NO_ERROR)
+		majorVersion = 2;
+
+	gl.getIntegerv(GL_MINOR_VERSION, &minorVersion);
+	if (gl.getError() != GL_NO_ERROR)
+		minorVersion = 0;
+
+	return (majorVersion > requiredMajor) || (majorVersion == requiredMajor && minorVersion >= requiredMinor);
+}
+
+// Check support for GL_* and DEQP_* extensions
+static bool checkExtensionSupport (const ContextInfo& ctxInfo, const RenderContext& ctx, const std::string& extension)
+{
+	if (de::beginsWith(extension, "GL_"))
+		return ctxInfo.isExtensionSupported(extension.c_str());
+	else if (extension == "DEQP_gles3_core_compatible")
+		return detectGLESCompatibleContext(ctx, 3, 0);
+	else if (extension == "DEQP_gles31_core_compatible")
+		return detectGLESCompatibleContext(ctx, 3, 1);
+	else
+	{
+		DE_ASSERT(false);
+		return false;
+	}
+}
+
+std::string getExtensionDescription (const std::string& extension)
+{
+	if (de::beginsWith(extension, "GL_"))
+		return extension;
+	else if (extension == "DEQP_gles3_core_compatible")
+		return "GLES3 compatible context";
+	else if (extension == "DEQP_gles31_core_compatible")
+		return "GLES3.1 compatible context";
+	else
+	{
+		DE_ASSERT(false);
+		return "";
+	}
+}
+
 void addFormats (FormatDB& db, FormatEntries stdFmts)
 {
 	for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++)
@@ -196,7 +248,7 @@
 		{
 			for (std::set<std::string>::const_iterator extIt = requiredExtensions.begin(); extIt != requiredExtensions.end(); ++extIt)
 			{
-				if (!ctxInfo->isExtensionSupported(extIt->c_str()))
+				if (!checkExtensionSupport(*ctxInfo, *ctx, *extIt))
 				{
 					supported = false;
 					break;
diff --git a/modules/glshared/glsFboUtil.hpp b/modules/glshared/glsFboUtil.hpp
index c6a14e7..f0788ac 100644
--- a/modules/glshared/glsFboUtil.hpp
+++ b/modules/glshared/glsFboUtil.hpp
@@ -181,10 +181,12 @@
 
 typedef Range<FormatExtEntry>						FormatExtEntries;
 
-void				addFormats			(FormatDB& db, FormatEntries stdFmts);
-void				addExtFormats		(FormatDB& db, FormatExtEntries extFmts,
-										 const glu::RenderContext* ctx);
-glu::TransferFormat	transferImageFormat	(const ImageFormat& imgFormat);
+// Accepts GL_* and DEQP_* extension strings and converts DEQP_* strings to a human readable string
+std::string			getExtensionDescription		(const std::string& extensionName);
+
+void				addFormats					(FormatDB& db, FormatEntries stdFmts);
+void				addExtFormats				(FormatDB& db, FormatExtEntries extFmts, const glu::RenderContext* ctx);
+glu::TransferFormat	transferImageFormat			(const ImageFormat& imgFormat);
 
 namespace config
 {