Merge "Fix EGL negative api eglMakeCurrent test."
diff --git a/framework/delibs/decpp/deStringUtil.cpp b/framework/delibs/decpp/deStringUtil.cpp
index c5e0166..14fccaa 100644
--- a/framework/delibs/decpp/deStringUtil.cpp
+++ b/framework/delibs/decpp/deStringUtil.cpp
@@ -22,6 +22,7 @@
*//*--------------------------------------------------------------------*/
#include "deStringUtil.hpp"
+#include "deString.h"
#include <algorithm>
#include <iterator>
@@ -113,6 +114,22 @@
return s.str();
}
+bool beginsWith (const std::string& s, const std::string& prefix)
+{
+ return deStringBeginsWith(s.c_str(), prefix.c_str());
+}
+
+bool endsWith (const std::string& s, const std::string& suffix)
+{
+ if (suffix.length() > s.length())
+ return false;
+ else
+ {
+ const std::string::size_type offset = s.length() - suffix.length();
+ return s.find(suffix, offset) == offset;
+ }
+}
+
char toUpper (char c)
{
return std::toupper(c, std::locale::classic());
@@ -156,6 +173,25 @@
DE_TEST_ASSERT(floatToString(4, 1) == "4.0");
+ DE_TEST_ASSERT(beginsWith("foobar", "foobar"));
+ DE_TEST_ASSERT(beginsWith("foobar", "foo"));
+ DE_TEST_ASSERT(beginsWith("foobar", "f"));
+ DE_TEST_ASSERT(beginsWith("foobar", ""));
+ DE_TEST_ASSERT(beginsWith("", ""));
+ DE_TEST_ASSERT(!beginsWith("foobar", "bar"));
+ DE_TEST_ASSERT(!beginsWith("foobar", "foobarbaz"));
+ DE_TEST_ASSERT(!beginsWith("", "foo"));
+
+ DE_TEST_ASSERT(endsWith("foobar", "foobar"));
+ DE_TEST_ASSERT(endsWith("foobar", "bar"));
+ DE_TEST_ASSERT(endsWith("foobar", "r"));
+ DE_TEST_ASSERT(endsWith("foobar", ""));
+ DE_TEST_ASSERT(endsWith("", ""));
+ DE_TEST_ASSERT(!endsWith("foobar", "foo"));
+ DE_TEST_ASSERT(!endsWith("foobar", "bazfoobar"));
+ DE_TEST_ASSERT(!endsWith("foobar", "foobarbaz"));
+ DE_TEST_ASSERT(!endsWith("", "foo"));
+
DE_TEST_ASSERT(toUpper('a') == 'A');
DE_TEST_ASSERT(toUpper('A') == 'A');
DE_TEST_ASSERT(toLower('a') == 'a');
diff --git a/framework/delibs/decpp/deStringUtil.hpp b/framework/delibs/decpp/deStringUtil.hpp
index 68614d8..343619c 100644
--- a/framework/delibs/decpp/deStringUtil.hpp
+++ b/framework/delibs/decpp/deStringUtil.hpp
@@ -47,6 +47,8 @@
std::string capitalize (const std::string& s);
std::vector<std::string> splitString (const std::string& s, char delim='\0');
std::string floatToString (float val, int precision);
+bool beginsWith (const std::string& s, const std::string& prefix);
+bool endsWith (const std::string& s, const std::string& suffix);
char toUpper (char c);
char toLower (char c);
bool isUpper (char c);
diff --git a/modules/gles2/functional/es2fFboCompletenessTests.cpp b/modules/gles2/functional/es2fFboCompletenessTests.cpp
index 5a67f8d..63be7b3 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,12 +154,47 @@
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
{
public:
- ES2Checker (void) : m_width(-1), m_height(-1) {}
+ ES2Checker (const glu::RenderContext& ctx);
void check (GLenum attPoint, const Attachment& att,
const Image* image);
private:
@@ -135,7 +202,14 @@
GLsizei m_height; //< The common height of images
};
-void ES2Checker::check(GLenum attPoint, const Attachment& att, const Image* image)
+ES2Checker::ES2Checker (const glu::RenderContext& ctx)\
+ : Checker (ctx)
+ , m_width (-1)
+ , m_height (-1)
+{
+}
+
+void ES2Checker::check (GLenum attPoint, const Attachment& att, const Image* image)
{
DE_UNREF(attPoint);
DE_UNREF(att);
@@ -145,10 +219,16 @@
m_width = image->width;
m_height = image->height;
}
- else
+ else if (image->width != m_width || image->height != m_height)
{
- require(image->width == m_width && image->height == m_height,
- GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
+ // Since GLES3 is "backwards compatible" to GLES2, we might actually be running
+ // on a GLES3 context. On GLES3, FRAMEBUFFER_INCOMPLETE_DIMENSIONS is not generated
+ // if attachments have different sizes.
+ if (!gls::FboUtil::checkExtensionSupport(m_renderCtx, "DEQP_gles3_core_compatible"))
+ {
+ // running on GLES2
+ addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS, "Sizes of attachments differ");
+ }
}
// GLES2, 4.4.5: "some implementations may not support rendering to
// particular combinations of internal formats. If the combination of
@@ -157,7 +237,7 @@
// under the clause labeled FRAMEBUFFER_UNSUPPORTED."
//
// Hence it is _always_ allowed to report FRAMEBUFFER_UNSUPPORTED.
- canRequire(false, GL_FRAMEBUFFER_UNSUPPORTED);
+ addPotentialFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Particular format combinations need not to be supported");
}
struct FormatCombination
@@ -204,7 +284,7 @@
if (fmt.format == GL_NONE)
return GL_NONE;
- const FormatFlags flags = m_ctx.getMinFormats().getFormatInfo(fmt, ANY_FORMAT);
+ const FormatFlags flags = m_ctx.getCoreFormats().getFormatInfo(fmt);
const bool rbo = (flags & RENDERBUFFER_VALID) != 0;
// exactly one of renderbuffer and texture is supported by vanilla GLES2 formats
DE_ASSERT(rbo != ((flags & TEXTURE_VALID) != 0));
@@ -214,7 +294,7 @@
IterateResult SupportedCombinationTest::iterate (void)
{
- const FormatDB& db = m_ctx.getMinFormats();
+ const FormatDB& db = m_ctx.getCoreFormats();
const ImageFormat none = ImageFormat::none();
Formats colorFmts = db.getFormats(COLOR_RENDERABLE);
Formats depthFmts = db.getFormats(DEPTH_RENDERABLE);
@@ -254,9 +334,10 @@
return STOP;
}
-class ES2CheckerFactory : public CheckerFactory {
+class ES2CheckerFactory : public CheckerFactory
+{
public:
- Checker* createChecker (void) { return new ES2Checker(); }
+ Checker* createChecker (const glu::RenderContext& ctx) { return new ES2Checker(ctx); }
};
class TestGroup : public TestCaseGroup
diff --git a/modules/gles3/functional/es3fFboCompletenessTests.cpp b/modules/gles3/functional/es3fFboCompletenessTests.cpp
index b392f51..0e06a18 100644
--- a/modules/gles3/functional/es3fFboCompletenessTests.cpp
+++ b/modules/gles3/functional/es3fFboCompletenessTests.cpp
@@ -136,26 +136,47 @@
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
{
public:
- ES3Checker (void)
- : m_numSamples (-1)
+ ES3Checker (const glu::RenderContext& ctx)
+ : Checker (ctx)
+ , m_numSamples (-1)
, m_depthStencilImage (0)
, m_depthStencilType (GL_NONE) {}
void check (GLenum attPoint, const Attachment& att, const Image* image);
@@ -191,16 +212,16 @@
// Either all attachments are zero-sample renderbuffers and/or
// textures, or none of them are.
- require((m_numSamples == 0) == (imgSamples == 0),
- GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
+ if ((m_numSamples == 0) != (imgSamples == 0))
+ addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Mixed multi- and single-sampled attachments");
// If the attachments requested a different number of samples, the
// implementation is allowed to report this as incomplete. However, it
// is also possible that despite the different requests, the
// implementation allocated the same number of samples to both. Hence
// reporting the framebuffer as complete is also legal.
- canRequire(m_numSamples == imgSamples,
- GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
+ if (m_numSamples != imgSamples)
+ addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Number of samples differ");
}
// "Depth and stencil attachments, if present, are the same image."
@@ -212,9 +233,10 @@
m_depthStencilType = attachmentType(att);
}
else
- require(m_depthStencilImage == att.imageName &&
- m_depthStencilType == attachmentType(att),
- GL_FRAMEBUFFER_UNSUPPORTED);
+ {
+ if (m_depthStencilImage != att.imageName || m_depthStencilType != attachmentType(att))
+ addFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Depth and stencil attachments are not the same image");
+ }
}
}
@@ -413,7 +435,7 @@
class ES3CheckerFactory : public CheckerFactory
{
public:
- Checker* createChecker (void) { return new ES3Checker(); }
+ Checker* createChecker (const glu::RenderContext& ctx) { return new ES3Checker(ctx); }
};
class TestGroup : public TestCaseGroup
diff --git a/modules/gles31/functional/es31fProgramInterfaceDefinition.cpp b/modules/gles31/functional/es31fProgramInterfaceDefinition.cpp
index 88ae724..6d8f737 100644
--- a/modules/gles31/functional/es31fProgramInterfaceDefinition.cpp
+++ b/modules/gles31/functional/es31fProgramInterfaceDefinition.cpp
@@ -26,6 +26,7 @@
#include "gluVarType.hpp"
#include "gluShaderProgram.hpp"
#include "deSTLUtil.hpp"
+#include "deStringUtil.hpp"
#include "glwEnums.hpp"
#include <set>
@@ -634,7 +635,7 @@
for (int ndx = 0; ndx < (int)m_xfbVaryings.size(); ++ndx)
{
// user-defined
- if (m_xfbVaryings[ndx].find("gl_") != 0)
+ if (!de::beginsWith(m_xfbVaryings[ndx], "gl_"))
{
std::vector<ProgramInterfaceDefinition::VariablePathComponent> path;
if (!findProgramVariablePathByPathName(path, this, m_xfbVaryings[ndx], VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(this), glu::STORAGE_OUT)))
diff --git a/modules/gles31/functional/es31fProgramInterfaceQueryTestCase.cpp b/modules/gles31/functional/es31fProgramInterfaceQueryTestCase.cpp
index 15c6431..778ef6f 100644
--- a/modules/gles31/functional/es31fProgramInterfaceQueryTestCase.cpp
+++ b/modules/gles31/functional/es31fProgramInterfaceQueryTestCase.cpp
@@ -46,14 +46,6 @@
using ProgramInterfaceDefinition::VariablePathComponent;
using ProgramInterfaceDefinition::VariableSearchFilter;
-static bool stringEndsWith (const std::string& str, const std::string& suffix)
-{
- if (suffix.length() > str.length())
- return false;
- else
- return str.substr(str.length() - suffix.length()) == suffix;
-}
-
static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage)
{
switch (storage)
@@ -1966,7 +1958,7 @@
if (recoveryStrategies[strategyNdx].removeTrailingArray)
{
- if (stringEndsWith(resourceName, "[0]"))
+ if (de::endsWith(resourceName, "[0]"))
simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
else
continue;
diff --git a/modules/gles31/functional/es31fProgramInterfaceQueryTests.cpp b/modules/gles31/functional/es31fProgramInterfaceQueryTests.cpp
index 0bc1efc..bfc85d9 100644
--- a/modules/gles31/functional/es31fProgramInterfaceQueryTests.cpp
+++ b/modules/gles31/functional/es31fProgramInterfaceQueryTests.cpp
@@ -52,14 +52,6 @@
namespace
{
-static bool stringEndsWith (const std::string& str, const std::string& suffix)
-{
- if (suffix.length() > str.length())
- return false;
- else
- return str.substr(str.length() - suffix.length()) == suffix;
-}
-
static int getTypeSize (glu::DataType type)
{
if (type == glu::TYPE_FLOAT)
@@ -1106,7 +1098,7 @@
{
for (int ndx = 0; ndx < (int)referenceResources.size(); ++ndx)
{
- if (stringEndsWith(referenceResources[ndx], "[0]"))
+ if (de::endsWith(referenceResources[ndx], "[0]"))
{
const std::string queryString = referenceResources[ndx].substr(0, referenceResources[ndx].length()-3);
const glw::GLuint index = gl.getProgramResourceIndex(program, programInterface, queryString.c_str());
@@ -1233,7 +1225,7 @@
if (arrayedInterface && isImplicitlySizedArray)
{
// omit implicit arrayness from name, i.e. remove trailing "_array"
- DE_ASSERT(stringEndsWith(buf, "_array"));
+ DE_ASSERT(de::endsWith(buf, "_array"));
buf = buf.substr(0, buf.length() - 6);
}
diff --git a/modules/gles31/functional/es31fTessellationTests.cpp b/modules/gles31/functional/es31fTessellationTests.cpp
index b17463f..f3f938a 100644
--- a/modules/gles31/functional/es31fTessellationTests.cpp
+++ b/modules/gles31/functional/es31fTessellationTests.cpp
@@ -5861,10 +5861,16 @@
const glu::VarType highpFloat (glu::TYPE_FLOAT, glu::PRECISION_HIGHP);
glu::StructType& structType = m_structTypes.back();
const glu::VarType structVarType (&structType);
+ bool usedStruct = false;
structType.addMember("x", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
structType.addMember("y", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
- structType.addMember("z", glu::VarType(highpFloat, 2));
+
+ if (useBlock)
+ {
+ // It is illegal to have a structure containing an array as an output variable
+ structType.addMember("z", glu::VarType(highpFloat, 2));
+ }
if (useBlock)
{
@@ -5876,20 +5882,32 @@
m_tcsOutputs.push_back (SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "tcBlock", blockMembers)));
m_tesInputs.push_back (SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "teBlock", blockMembers)));
+
+ usedStruct = true;
}
else
{
const Variable var0("in_te_s", structVarType, m_ioType != IO_TYPE_PER_PATCH);
const Variable var1("in_te_f", highpFloat, m_ioType != IO_TYPE_PER_PATCH);
- m_tcsOutputs.push_back (SharedPtr<TopLevelObject>(new Variable(var0)));
- m_tesInputs.push_back (SharedPtr<TopLevelObject>(new Variable(var0)));
+ if (m_ioType != IO_TYPE_PER_PATCH_ARRAY)
+ {
+ // Arrays of structures are disallowed, add struct cases only if not arrayed variable
+ m_tcsOutputs.push_back (SharedPtr<TopLevelObject>(new Variable(var0)));
+ m_tesInputs.push_back (SharedPtr<TopLevelObject>(new Variable(var0)));
+
+ usedStruct = true;
+ }
+
m_tcsOutputs.push_back (SharedPtr<TopLevelObject>(new Variable(var1)));
m_tesInputs.push_back (SharedPtr<TopLevelObject>(new Variable(var1)));
}
tcsDeclarations += "in " + Variable("in_tc_attr", highpFloat, true).declare(vertexAttrArrayInputSize);
- tcsDeclarations += de::toString(glu::declare(structType)) + ";\n";
+
+ if (usedStruct)
+ tcsDeclarations += de::toString(glu::declare(structType)) + ";\n";
+
tcsStatements += "\t{\n"
"\t\thighp float v = 1.3;\n";
diff --git a/modules/glshared/glsFboCompletenessTests.cpp b/modules/glshared/glsFboCompletenessTests.cpp
index fc93f49..cb84808 100644
--- a/modules/glshared/glsFboCompletenessTests.cpp
+++ b/modules/glshared/glsFboCompletenessTests.cpp
@@ -45,6 +45,7 @@
using tcu::TestNode;
using std::string;
using de::toString;
+using de::toLower;
using namespace deqp::gls::FboUtil;
using namespace deqp::gls::FboUtil::config;
typedef TestCase::IterateResult IterateResult;
@@ -58,14 +59,6 @@
namespace details
{
-// \todo [2013-12-04 lauri] Place in deStrUtil.hpp?
-
-string toLower (const string& str)
-{
- string ret;
- std::transform(str.begin(), str.end(), std::inserter(ret, ret.begin()), ::tolower);
- return ret;
-}
// The following extensions are applicable both to ES2 and ES3.
@@ -406,7 +399,7 @@
CheckerFactory& factory)
: m_testCtx (testCtx)
, m_renderCtx (renderCtx)
- , m_verifier (m_ctxFormats, factory)
+ , m_verifier (m_ctxFormats, factory, renderCtx)
, m_haveMultiColorAtts (false)
{
FormatExtEntries extRange = GLS_ARRAY_RANGE(s_esExtFormats);
@@ -415,15 +408,15 @@
void Context::addFormats (FormatEntries fmtRange)
{
- FboUtil::addFormats(m_minFormats, fmtRange);
+ FboUtil::addFormats(m_coreFormats, fmtRange);
FboUtil::addFormats(m_ctxFormats, fmtRange);
- FboUtil::addFormats(m_maxFormats, fmtRange);
+ FboUtil::addFormats(m_allFormats, fmtRange);
}
void Context::addExtFormats (FormatExtEntries extRange)
{
FboUtil::addExtFormats(m_ctxFormats, extRange, &m_renderCtx);
- FboUtil::addExtFormats(m_maxFormats, extRange, DE_NULL);
+ FboUtil::addExtFormats(m_allFormats, extRange, DE_NULL);
}
void TestBase::pass (void)
@@ -441,76 +434,249 @@
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, msg);
}
-static string statusName (GLenum status)
-{
- const char* errorName = getErrorName(status);
- if (status != GL_NO_ERROR && errorName != DE_NULL)
- return string(errorName) + " (during FBO initialization)";
-
- const char* fbStatusName = getFramebufferStatusName(status);
- if (fbStatusName != DE_NULL)
- return fbStatusName;
-
- return "unknown value (" + toString(status) + ")";
-}
-
const glw::Functions& gl (const TestBase& test)
{
return test.getContext().getRenderContext().getFunctions();
}
+static bool isFormatFeatureSupported (const FormatDB& db, const ImageFormat& format, FormatFlags feature)
+{
+ return db.isKnownFormat(format) && ((db.getFormatInfo(format) & feature) == feature);
+}
+
+static void logAffectingExtensions (const char* prefix, const FormatDB& db, const ImageFormat& format, FormatFlags feature, tcu::MessageBuilder& msg)
+{
+ const std::set<std::set<std::string> > rows = db.getFormatFeatureExtensions(format, feature);
+
+ for (std::set<std::set<std::string> >::const_iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt)
+ {
+ const std::set<std::string>& requiredExtensions = *rowIt;
+ std::set<std::string>::const_iterator it = requiredExtensions.begin();
+ std::string extName;
+
+ msg << prefix;
+
+ extName = *it++;
+ while (it != requiredExtensions.end())
+ {
+ msg << getExtensionDescription(extName);
+ extName = *it++;
+ msg << (it == requiredExtensions.end() ? " and " : ", ");
+ }
+
+ msg << getExtensionDescription(extName) << '\n';
+ }
+}
+
+static void logFormatInfo (const config::Framebuffer& fbo, const FormatDB& ctxFormats, const FormatDB& coreFormats, const FormatDB& allFormats, tcu::TestLog& log)
+{
+ static const struct
+ {
+ const char* name;
+ const FormatFlags flag;
+ } s_renderability[] =
+ {
+ { "color-renderable", COLOR_RENDERABLE },
+ { "depth-renderable", DEPTH_RENDERABLE },
+ { "stencil-renderable", STENCIL_RENDERABLE },
+ };
+
+ std::set<ImageFormat> formats;
+
+ for (config::TextureMap::const_iterator it = fbo.textures.begin(); it != fbo.textures.end(); ++it)
+ formats.insert(it->second->internalFormat);
+ for (config::RboMap::const_iterator it = fbo.rbos.begin(); it != fbo.rbos.end(); ++it)
+ formats.insert(it->second->internalFormat);
+
+ if (!formats.empty())
+ {
+ const tcu::ScopedLogSection supersection(log, "Format", "Format info");
+
+ for (std::set<ImageFormat>::const_iterator it = formats.begin(); it != formats.end(); ++it)
+ {
+ const tcu::ScopedLogSection section(log, "FormatInfo", de::toString(*it));
+
+ // texture validity
+ if (isFormatFeatureSupported(ctxFormats, *it, TEXTURE_VALID))
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Valid texture format\n";
+
+ if (isFormatFeatureSupported(coreFormats, *it, TEXTURE_VALID))
+ msg << "\t* core feature";
+ else
+ {
+ msg << "\t* defined in supported extension(s):\n";
+ logAffectingExtensions("\t\t- ", ctxFormats, *it, TEXTURE_VALID, msg);
+ }
+
+ msg << tcu::TestLog::EndMessage;
+ }
+ else
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Unsupported texture format\n";
+
+ if (isFormatFeatureSupported(allFormats, *it, TEXTURE_VALID))
+ {
+ msg << "\t* requires any of the extensions or combinations:\n";
+ logAffectingExtensions("\t\t- ", allFormats, *it, TEXTURE_VALID, msg);
+ }
+ else
+ msg << "\t* no extension can make this format valid";
+
+ msg << tcu::TestLog::EndMessage;
+ }
+
+ // RBO validity
+ if (isFormatFeatureSupported(ctxFormats, *it, RENDERBUFFER_VALID))
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Valid renderbuffer format\n";
+
+ if (isFormatFeatureSupported(coreFormats, *it, RENDERBUFFER_VALID))
+ msg << "\t* core feature";
+ else
+ {
+ msg << "\t* defined in supported extension(s):\n";
+ logAffectingExtensions("\t\t- ", ctxFormats, *it, RENDERBUFFER_VALID, msg);
+ }
+
+ msg << tcu::TestLog::EndMessage;
+ }
+ else
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Unsupported renderbuffer format\n";
+
+ if (isFormatFeatureSupported(allFormats, *it, RENDERBUFFER_VALID))
+ {
+ msg << "\t* requires any of the extensions or combinations:\n";
+ logAffectingExtensions("\t\t- ", allFormats, *it, RENDERBUFFER_VALID, msg);
+ }
+ else
+ msg << "\t* no extension can make this format valid";
+
+ msg << tcu::TestLog::EndMessage;
+ }
+
+ // renderability
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_renderability); ++ndx)
+ {
+ if (isFormatFeatureSupported(ctxFormats, *it, s_renderability[ndx].flag | REQUIRED_RENDERABLE))
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Format is " << s_renderability[ndx].name << "\n";
+
+ if (isFormatFeatureSupported(coreFormats, *it, s_renderability[ndx].flag | REQUIRED_RENDERABLE))
+ msg << "\t* core feature";
+ else
+ {
+ msg << "\t* defined in supported extension(s):\n";
+ logAffectingExtensions("\t\t- ", ctxFormats, *it, s_renderability[ndx].flag | REQUIRED_RENDERABLE, msg);
+ }
+
+ msg << tcu::TestLog::EndMessage;
+ }
+ else if (isFormatFeatureSupported(ctxFormats, *it, s_renderability[ndx].flag))
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Format is allowed to be " << s_renderability[ndx].name << " but not required\n";
+
+ if (isFormatFeatureSupported(coreFormats, *it, s_renderability[ndx].flag))
+ msg << "\t* core feature";
+ else if (isFormatFeatureSupported(allFormats, *it, s_renderability[ndx].flag))
+ {
+ msg << "\t* extensions that would make format " << s_renderability[ndx].name << ":\n";
+ logAffectingExtensions("\t\t- ", allFormats, *it, s_renderability[ndx].flag, msg);
+ }
+ else
+ msg << "\t* no extension can make this format " << s_renderability[ndx].name;
+
+ msg << tcu::TestLog::EndMessage;
+ }
+ else
+ {
+ tcu::MessageBuilder msg(&log);
+ msg << "* Format is NOT " << s_renderability[ndx].name << "\n";
+
+ if (isFormatFeatureSupported(allFormats, *it, s_renderability[ndx].flag))
+ {
+ if (isFormatFeatureSupported(allFormats, *it, s_renderability[ndx].flag | REQUIRED_RENDERABLE))
+ {
+ msg << "\t* extensions that would make format " << s_renderability[ndx].name << ":\n";
+ logAffectingExtensions("\t\t- ", allFormats, *it, s_renderability[ndx].flag | REQUIRED_RENDERABLE, msg);
+ }
+ else
+ {
+ msg << "\t* extensions that are allowed to make format " << s_renderability[ndx].name << ":\n";
+ logAffectingExtensions("\t\t- ", allFormats, *it, s_renderability[ndx].flag, msg);
+ }
+ }
+ else
+ msg << "\t* no extension can make this format " << s_renderability[ndx].name;
+
+ msg << tcu::TestLog::EndMessage;
+ }
+ }
+ }
+ }
+}
+
IterateResult TestBase::iterate (void)
{
- glu::Framebuffer fbo(m_ctx.getRenderContext());
- FboBuilder builder(*fbo, GL_FRAMEBUFFER, gl(*this));
- const IterateResult ret = build(builder);
- const StatusCodes statuses = m_ctx.getVerifier().validStatusCodes(builder);
+ glu::Framebuffer fbo (m_ctx.getRenderContext());
+ FboBuilder builder (*fbo, GL_FRAMEBUFFER, gl(*this));
+ const IterateResult ret = build(builder);
+ const ValidStatusCodes reference = m_ctx.getVerifier().validStatusCodes(builder);
+ const GLenum errorCode = builder.getError();
- GLenum glStatus = builder.getError();
- if (glStatus == GL_NO_ERROR)
- glStatus = gl(*this).checkFramebufferStatus(GL_FRAMEBUFFER);
+ logFramebufferConfig(builder, m_testCtx.getLog());
+ logFormatInfo(builder, m_ctx.getCtxFormats(), m_ctx.getCoreFormats(), m_ctx.getAllFormats(), m_testCtx.getLog());
+ reference.logRules(m_testCtx.getLog());
+ reference.logLegalResults(m_testCtx.getLog());
// \todo [2013-12-04 lauri] Check if drawing operations succeed.
- StatusCodes::const_iterator it = statuses.begin();
- GLenum err = *it++;
- logFramebufferConfig(builder, m_testCtx.getLog());
-
- MessageBuilder msg(&m_testCtx.getLog());
-
- msg << "Expected ";
- if (it != statuses.end())
+ if (errorCode != GL_NO_ERROR)
{
- msg << "one of ";
- while (it != statuses.end())
- {
- msg << statusName(err);
- err = *it++;
- msg << (it == statuses.end() ? " or " : ", ");
- }
- }
- msg << statusName(err) << "." << TestLog::EndMessage;
- m_testCtx.getLog() << TestLog::Message << "Received " << statusName(glStatus)
- << "." << TestLog::EndMessage;
+ m_testCtx.getLog()
+ << TestLog::Message
+ << "Received " << glu::getErrorStr(errorCode) << " (during FBO initialization)."
+ << TestLog::EndMessage;
- if (!contains(statuses, glStatus))
- {
- // The returned status value was not acceptable.
- if (glStatus == GL_FRAMEBUFFER_COMPLETE)
- fail("Framebuffer checked as complete, expected incomplete");
- else if (statuses.size() == 1 && contains(statuses, GL_FRAMEBUFFER_COMPLETE))
- fail("Framebuffer checked is incomplete, expected complete");
+ if (reference.isErrorCodeValid(errorCode))
+ pass();
+ else if (reference.isErrorCodeRequired(GL_NO_ERROR))
+ fail(("Expected no error but got " + de::toString(glu::getErrorStr(errorCode))).c_str());
else
- // An incomplete status is allowed, but not _this_ incomplete status.
- fail("Framebuffer checked as incomplete, but with wrong status");
- }
- else if (glStatus != GL_FRAMEBUFFER_COMPLETE &&
- contains(statuses, GL_FRAMEBUFFER_COMPLETE))
- {
- qualityWarning("Framebuffer object could have checked as complete but did not.");
+ fail("Got wrong error code");
}
else
- pass();
+ {
+ const GLenum fboStatus = gl(*this).checkFramebufferStatus(GL_FRAMEBUFFER);
+ const bool validStatus = reference.isFBOStatusValid(fboStatus);
+
+ m_testCtx.getLog()
+ << TestLog::Message
+ << "Received " << glu::getFramebufferStatusStr(fboStatus) << "."
+ << TestLog::EndMessage;
+
+ if (!validStatus)
+ {
+ if (fboStatus == GL_FRAMEBUFFER_COMPLETE)
+ fail("Framebuffer checked as complete, expected incomplete");
+ else if (reference.isFBOStatusRequired(GL_FRAMEBUFFER_COMPLETE))
+ fail("Framebuffer checked is incomplete, expected complete");
+ else
+ // An incomplete status is allowed, but not _this_ incomplete status.
+ fail("Framebuffer checked as incomplete, but with wrong status");
+ }
+ else if (fboStatus != GL_FRAMEBUFFER_COMPLETE && reference.isFBOStatusValid(GL_FRAMEBUFFER_COMPLETE))
+ qualityWarning("Framebuffer object could have checked as complete but did not.");
+ else
+ pass();
+ }
return ret;
}
@@ -530,7 +696,7 @@
// Prefer a standard format, if there is one, but if not, use a format
// provided by an extension.
- Formats formats = m_ctx.getMinFormats().getFormats(formatFlag(attPoint) |
+ Formats formats = m_ctx.getCoreFormats().getFormats(formatFlag(attPoint) |
formatFlag(bufType));
Formats::const_iterator it = formats.begin();
if (it == formats.end())
@@ -638,7 +804,7 @@
{
GLenum attPoint;
GLenum bufType;
- ImageFormat format;
+ ImageFormat format;
static string getName (const RenderableParams& params)
{
return formatName(params.format);
@@ -709,7 +875,7 @@
: ParamTest<AttachmentParams> (group, params) {}
protected:
- IterateResult build (FboBuilder& builder);
+ IterateResult build (FboBuilder& builder);
void makeDepthAndStencil (FboBuilder& builder);
};
@@ -722,7 +888,7 @@
// image for both attachments.
const FormatFlags flags =
DEPTH_RENDERABLE | STENCIL_RENDERABLE | formatFlag(m_params.stencilKind);
- const Formats& formats = m_ctx.getMinFormats().getFormats(flags);
+ const Formats& formats = m_ctx.getCoreFormats().getFormats(flags);
Formats::const_iterator it = formats.begin();
if (it != formats.end())
{
@@ -816,9 +982,9 @@
m_testCtx, "texture", "Tests for texture formats");
static const struct AttPoint {
- GLenum attPoint;
- const char* name;
- const char* desc;
+ GLenum attPoint;
+ const char* name;
+ const char* desc;
} attPoints[] =
{
{ GL_COLOR_ATTACHMENT0, "color0", "Tests for color attachments" },
@@ -828,8 +994,8 @@
// At each attachment point, iterate through all the possible formats to
// detect both false positives and false negatives.
- const Formats rboFmts = m_maxFormats.getFormats(ANY_FORMAT);
- const Formats texFmts = m_maxFormats.getFormats(ANY_FORMAT);
+ const Formats rboFmts = m_allFormats.getFormats(ANY_FORMAT);
+ const Formats texFmts = m_allFormats.getFormats(ANY_FORMAT);
for (const AttPoint* it = DE_ARRAY_BEGIN(attPoints); it != DE_ARRAY_END(attPoints); it++)
{
diff --git a/modules/glshared/glsFboCompletenessTests.hpp b/modules/glshared/glsFboCompletenessTests.hpp
index b284731..bc3cd3b 100644
--- a/modules/glshared/glsFboCompletenessTests.hpp
+++ b/modules/glshared/glsFboCompletenessTests.hpp
@@ -63,8 +63,9 @@
RenderContext& getRenderContext (void) const { return m_renderCtx; }
TestContext& getTestContext (void) const { return m_testCtx; }
const FboVerifier& getVerifier (void) const { return m_verifier; }
- const FormatDB& getMinFormats (void) const { return m_minFormats; }
+ const FormatDB& getCoreFormats (void) const { return m_coreFormats; }
const FormatDB& getCtxFormats (void) const { return m_ctxFormats; }
+ const FormatDB& getAllFormats (void) const { return m_allFormats; }
bool haveMultiColorAtts (void) const { return m_haveMultiColorAtts; }
void setHaveMulticolorAtts (bool have) { m_haveMultiColorAtts = have; }
void addFormats (FormatEntries fmtRange);
@@ -75,9 +76,9 @@
private:
TestContext& m_testCtx;
RenderContext& m_renderCtx;
- FormatDB m_minFormats;
+ FormatDB m_coreFormats;
FormatDB m_ctxFormats;
- FormatDB m_maxFormats;
+ FormatDB m_allFormats;
FboVerifier m_verifier;
bool m_haveMultiColorAtts;
};
diff --git a/modules/glshared/glsFboUtil.cpp b/modules/glshared/glsFboUtil.cpp
index 9d312a0..749d25e 100644
--- a/modules/glshared/glsFboUtil.cpp
+++ b/modules/glshared/glsFboUtil.cpp
@@ -28,6 +28,7 @@
#include "gluTextureUtil.hpp"
#include "gluStrUtil.hpp"
#include "deStringUtil.hpp"
+#include "deSTLUtil.hpp"
#include <sstream>
using namespace glw;
@@ -63,18 +64,64 @@
namespace FboUtil
{
-
-void FormatDB::addFormat (ImageFormat format, FormatFlags newFlags)
+#if defined(DE_DEBUG)
+static bool isFramebufferStatus (glw::GLenum fboStatus)
{
- FormatFlags& flags = m_map[format];
+ return glu::getFramebufferStatusName(fboStatus) != DE_NULL;
+}
+
+static bool isErrorCode (glw::GLenum errorCode)
+{
+ return glu::getErrorName(errorCode) != DE_NULL;
+}
+#endif
+
+std::ostream& operator<< (std::ostream& stream, const ImageFormat& format)
+{
+ if (format.unsizedType == GL_NONE)
+ {
+ // sized format
+ return stream << glu::getPixelFormatStr(format.format);
+ }
+ else
+ {
+ // unsized format
+ return stream << "(format = " << glu::getPixelFormatStr(format.format) << ", type = " << glu::getTypeStr(format.unsizedType) << ")";
+ }
+}
+
+void FormatDB::addCoreFormat (ImageFormat format, FormatFlags newFlags)
+{
+ FormatFlags& flags = m_formatFlags[format];
flags = FormatFlags(flags | newFlags);
}
+void FormatDB::addExtensionFormat (ImageFormat format, FormatFlags newFlags, const std::set<std::string>& requiredExtensions)
+{
+ DE_ASSERT(!requiredExtensions.empty());
+
+ {
+ FormatFlags& flags = m_formatFlags[format];
+ flags = FormatFlags(flags | newFlags);
+ }
+
+ {
+ std::set<ExtensionInfo>& extensionInfo = m_formatExtensions[format];
+ ExtensionInfo extensionRecord;
+
+ extensionRecord.flags = newFlags;
+ extensionRecord.requiredExtensions = requiredExtensions;
+
+ DE_ASSERT(!de::contains(extensionInfo, extensionRecord)); // extensions specified only once
+ extensionInfo.insert(extensionRecord);
+ }
+}
+
// Not too fast at the moment, might consider indexing?
Formats FormatDB::getFormats (FormatFlags requirements) const
{
Formats ret;
- for (FormatMap::const_iterator it = m_map.begin(); it != m_map.end(); it++)
+ for (FormatMap::const_iterator it = m_formatFlags.begin(); it != m_formatFlags.end(); it++)
{
if ((it->second & requirements) == requirements)
ret.insert(it->first);
@@ -82,9 +129,94 @@
return ret;
}
-FormatFlags FormatDB::getFormatInfo (ImageFormat format, FormatFlags fallback) const
+bool FormatDB::isKnownFormat (ImageFormat format) const
{
- return lookupDefault(m_map, format, fallback);
+ return de::contains(m_formatFlags, format);
+}
+
+FormatFlags FormatDB::getFormatInfo (ImageFormat format) const
+{
+ DE_ASSERT(de::contains(m_formatFlags, format));
+ return de::lookup(m_formatFlags, format);
+}
+
+std::set<std::set<std::string> > FormatDB::getFormatFeatureExtensions (ImageFormat format, FormatFlags requirements) const
+{
+ DE_ASSERT(de::contains(m_formatExtensions, format));
+
+ const std::set<ExtensionInfo>& extensionInfo = de::lookup(m_formatExtensions, format);
+ std::set<std::set<std::string> > ret;
+
+ for (std::set<ExtensionInfo>::const_iterator it = extensionInfo.begin(); it != extensionInfo.end(); ++it)
+ {
+ if ((it->flags & requirements) == requirements)
+ ret.insert(it->requiredExtensions);
+ }
+
+ return ret;
+}
+
+bool FormatDB::ExtensionInfo::operator< (const ExtensionInfo& other) const
+{
+ return (requiredExtensions < other.requiredExtensions) ||
+ ((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);
+}
+
+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;
+ }
+}
+
+bool checkExtensionSupport (const RenderContext& ctx, const std::string& extension)
+{
+ const de::UniquePtr<ContextInfo> info(ContextInfo::create(ctx));
+ return checkExtensionSupport(*info, ctx, extension);
+}
+
+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)
@@ -92,34 +224,46 @@
for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++)
{
for (const FormatKey* it2 = it->second.begin(); it2 != it->second.end(); it2++)
- db.addFormat(formatKeyInfo(*it2), it->first);
+ db.addCoreFormat(formatKeyInfo(*it2), it->first);
}
}
void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const RenderContext* ctx)
{
const UniquePtr<ContextInfo> ctxInfo(ctx != DE_NULL ? ContextInfo::create(*ctx) : DE_NULL);
- for (const FormatExtEntry* it = extFmts.begin(); it != extFmts.end(); it++)
+ for (const FormatExtEntry* entryIt = extFmts.begin(); entryIt != extFmts.end(); entryIt++)
{
- bool supported = true;
- if (ctxInfo)
+ bool supported = true;
+ std::set<std::string> requiredExtensions;
+
+ // parse required extensions
{
- istringstream tokenStream(string(it->extensions));
+ istringstream tokenStream(string(entryIt->extensions));
istream_iterator<string> tokens((tokenStream)), end;
while (tokens != end)
{
- if (!ctxInfo->isExtensionSupported(tokens->c_str()))
+ requiredExtensions.insert(*tokens);
+ ++tokens;
+ }
+ }
+
+ // check support
+ if (ctxInfo)
+ {
+ for (std::set<std::string>::const_iterator extIt = requiredExtensions.begin(); extIt != requiredExtensions.end(); ++extIt)
+ {
+ if (!checkExtensionSupport(*ctxInfo, *ctx, *extIt))
{
supported = false;
break;
}
- ++tokens;
}
}
+
if (supported)
- for (const FormatKey* i2 = it->formats.begin(); i2 != it->formats.end(); i2++)
- db.addFormat(formatKeyInfo(*i2), FormatFlags(it->flags));
+ for (const FormatKey* i2 = entryIt->formats.begin(); i2 != entryIt->formats.end(); i2++)
+ db.addExtensionFormat(formatKeyInfo(*i2), FormatFlags(entryIt->flags), requiredExtensions);
}
}
@@ -143,6 +287,19 @@
}
}
+static FormatFlags getAttachmentRenderabilityFlag (GLenum attachment)
+{
+ switch (attachment)
+ {
+ case GL_STENCIL_ATTACHMENT: return STENCIL_RENDERABLE;
+ case GL_DEPTH_ATTACHMENT: return DEPTH_RENDERABLE;
+
+ default:
+ DE_ASSERT(attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15);
+ return COLOR_RENDERABLE;
+ }
+}
+
namespace config {
GLsizei imageNumSamples (const Image& img)
@@ -332,45 +489,67 @@
// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
// number of layers in the texture.
- cctx.require(textureLayer(*texAtt) < ltex->numLayers,
- GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
+ if (textureLayer(*texAtt) >= ltex->numLayers)
+ cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attached layer index is larger than present");
}
// "The width and height of image are non-zero."
- cctx.require(image->width > 0 && image->height > 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
+ if (image->width == 0 || image->height == 0)
+ cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Width and height of an image are not non-zero");
// Check for renderability
- FormatFlags flags = db.getFormatInfo(image->internalFormat, ANY_FORMAT);
- // If the format does not have the proper renderability flag, the
- // completeness check _must_ fail.
- cctx.require((flags & formatFlag(attPoint)) != 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
- // If the format is only optionally renderable, the completeness check _can_ fail.
- cctx.canRequire((flags & REQUIRED_RENDERABLE) != 0,
- GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
+ if (db.isKnownFormat(image->internalFormat))
+ {
+ const FormatFlags flags = db.getFormatInfo(image->internalFormat);
+
+ // If the format does not have the proper renderability flag, the
+ // completeness check _must_ fail.
+ if ((flags & getAttachmentRenderabilityFlag(attPoint)) == 0)
+ cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not renderable in this attachment");
+ // If the format is only optionally renderable, the completeness check _can_ fail.
+ else if ((flags & REQUIRED_RENDERABLE) == 0)
+ cctx.addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not required renderable");
+ }
+ else
+ cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not legal");
}
} // namespace config
using namespace config;
-void Checker::require (bool condition, GLenum error)
+Checker::Checker (const glu::RenderContext& ctx)
+ : m_renderCtx(ctx)
{
- if (!condition)
- {
- m_statusCodes.erase(GL_FRAMEBUFFER_COMPLETE);
- m_statusCodes.insert(error);
- }
+ m_statusCodes.setAllowComplete(true);
}
-void Checker::canRequire (bool condition, GLenum error)
+void Checker::addGLError (glw::GLenum error, const char* description)
{
- if (!condition)
- m_statusCodes.insert(error);
+ m_statusCodes.addErrorCode(error, description);
+ m_statusCodes.setAllowComplete(false);
}
-FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory)
- : m_formats (formats)
- , m_factory (factory)
+void Checker::addPotentialGLError (glw::GLenum error, const char* description)
+{
+ m_statusCodes.addErrorCode(error, description);
+}
+
+void Checker::addFBOStatus (GLenum status, const char* description)
+{
+ m_statusCodes.addFBOErrorStatus(status, description);
+ m_statusCodes.setAllowComplete(false);
+}
+
+void Checker::addPotentialFBOStatus (GLenum status, const char* description)
+{
+ m_statusCodes.addFBOErrorStatus(status, description);
+}
+
+FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory, const glu::RenderContext& renderCtx)
+ : m_formats (formats)
+ , m_factory (factory)
+ , m_renderCtx (renderCtx)
{
}
@@ -391,37 +570,71 @@
* `glCheckFramebufferStatus` was ever called.
*
*//*--------------------------------------------------------------------*/
-StatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const
+ValidStatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const
{
const AttachmentMap& atts = fboConfig.attachments;
- const UniquePtr<Checker> cctx(m_factory.createChecker());
+ const UniquePtr<Checker> cctx(m_factory.createChecker(m_renderCtx));
for (TextureMap::const_iterator it = fboConfig.textures.begin();
it != fboConfig.textures.end(); it++)
{
- const FormatFlags flags =
- m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
- cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_ENUM);
- cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_OPERATION);
- cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_VALUE);
+ std::string errorDescription;
+
+ if (m_formats.isKnownFormat(it->second->internalFormat))
+ {
+ const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat);
+
+ if ((flags & TEXTURE_VALID) == 0)
+ errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a texture";
+ }
+ else if (it->second->internalFormat.unsizedType == GL_NONE)
+ {
+ // sized format
+ errorDescription = "Format " + de::toString(it->second->internalFormat) + " does not exist";
+ }
+ else
+ {
+ // unsized type-format pair
+ errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a legal format";
+ }
+
+ if (!errorDescription.empty())
+ {
+ cctx->addGLError(GL_INVALID_ENUM, errorDescription.c_str());
+ cctx->addGLError(GL_INVALID_OPERATION, errorDescription.c_str());
+ cctx->addGLError(GL_INVALID_VALUE, errorDescription.c_str());
+ }
}
for (RboMap::const_iterator it = fboConfig.rbos.begin(); it != fboConfig.rbos.end(); it++)
{
- const FormatFlags flags =
- m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
- cctx->require((flags & RENDERBUFFER_VALID) != 0, GL_INVALID_ENUM);
+ if (m_formats.isKnownFormat(it->second->internalFormat))
+ {
+ const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat);
+ if ((flags & RENDERBUFFER_VALID) == 0)
+ {
+ const std::string reason = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a renderbuffer";
+ cctx->addGLError(GL_INVALID_ENUM, reason.c_str());
+ }
+ }
+ else
+ {
+ const std::string reason = "Internal format " + de::toString(it->second->internalFormat) + " does not exist";
+ cctx->addGLError(GL_INVALID_ENUM, reason.c_str());
+ }
}
// "There is at least one image attached to the framebuffer."
- // TODO: support XXX_framebuffer_no_attachments
- cctx->require(!atts.empty(), GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
+ // \todo support XXX_framebuffer_no_attachments
+ if (atts.empty())
+ cctx->addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, "No images attached to the framebuffer");
for (AttachmentMap::const_iterator it = atts.begin(); it != atts.end(); it++)
{
const GLenum attPoint = it->first;
const Attachment& att = *it->second;
const Image* const image = fboConfig.getImage(attachmentType(att), att.imageName);
+
checkAttachmentCompleteness(*cctx, att, attPoint, image, m_formats);
cctx->check(it->first, *it->second, image);
}
@@ -443,9 +656,9 @@
switch (type)
{
case GL_TEXTURE:
- return lookupDefault(textures, imgName, DE_NULL);
+ return de::lookupDefault(textures, imgName, DE_NULL);
case GL_RENDERBUFFER:
- return lookupDefault(rbos, imgName, DE_NULL);
+ return de::lookupDefault(rbos, imgName, DE_NULL);
default:
DE_ASSERT(!"Bad image type");
}
@@ -473,7 +686,7 @@
logField(log, "Internal format", getPixelFormatName(img.internalFormat.format));
if (useType && type != GL_NONE)
logField(log, "Format type", getTypeName(type));
- logField(log, "Width", toString(img.width));
+ logField(log, "Width", toString(img.width));
logField(log, "Height", toString(img.height));
}
@@ -520,32 +733,22 @@
{
log << TestLog::Section("Framebuffer", "Framebuffer configuration");
- const string rboDesc = cfg.rbos.empty()
- ? "No renderbuffers were created"
- : "Renderbuffers created";
- log << TestLog::Section("Renderbuffers", rboDesc);
for (RboMap::const_iterator it = cfg.rbos.begin(); it != cfg.rbos.end(); ++it)
{
- const string num = toString(it->first);
- log << TestLog::Section(num, "Renderbuffer " + num);
- logRenderbuffer(*it->second, log);
- log << TestLog::EndSection;
- }
- log << TestLog::EndSection; // Renderbuffers
+ const string num = toString(it->first);
+ const tcu::ScopedLogSection subsection (log, num, "Renderbuffer " + num);
- const string texDesc = cfg.textures.empty()
- ? "No textures were created"
- : "Textures created";
- log << TestLog::Section("Textures", texDesc);
- for (TextureMap::const_iterator it = cfg.textures.begin();
- it != cfg.textures.end(); ++it)
- {
- const string num = toString(it->first);
- log << TestLog::Section(num, "Texture " + num);
- logTexture(*it->second, log);
- log << TestLog::EndSection;
+ logRenderbuffer(*it->second, log);
}
- log << TestLog::EndSection; // Textures
+
+ for (TextureMap::const_iterator it = cfg.textures.begin();
+ it != cfg.textures.end(); ++it)
+ {
+ const string num = toString(it->first);
+ const tcu::ScopedLogSection subsection (log, num, "Texture " + num);
+
+ logTexture(*it->second, log);
+ }
const string attDesc = cfg.attachments.empty()
? "Framebuffer has no attachments"
@@ -564,6 +767,166 @@
log << TestLog::EndSection; // Framebuffer
}
+ValidStatusCodes::ValidStatusCodes (void)
+ : m_allowComplete(false)
+{
+}
+
+bool ValidStatusCodes::isFBOStatusValid (glw::GLenum fboStatus) const
+{
+ if (fboStatus == GL_FRAMEBUFFER_COMPLETE)
+ return m_allowComplete;
+ else
+ {
+ // rule violation exists?
+ for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
+ {
+ if (m_errorStatuses[ndx].errorCode == fboStatus)
+ return true;
+ }
+ return false;
+ }
+}
+
+bool ValidStatusCodes::isFBOStatusRequired (glw::GLenum fboStatus) const
+{
+ if (fboStatus == GL_FRAMEBUFFER_COMPLETE)
+ return m_allowComplete && m_errorStatuses.empty();
+ else
+ // fboStatus is the only allowed error status and succeeding is forbidden
+ return !m_allowComplete && m_errorStatuses.size() == 1 && m_errorStatuses.front().errorCode == fboStatus;
+}
+
+bool ValidStatusCodes::isErrorCodeValid (glw::GLenum errorCode) const
+{
+ if (errorCode == GL_NO_ERROR)
+ return m_errorCodes.empty();
+ else
+ {
+ // rule violation exists?
+ for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
+ {
+ if (m_errorCodes[ndx].errorCode == errorCode)
+ return true;
+ }
+ return false;
+ }
+}
+
+bool ValidStatusCodes::isErrorCodeRequired (glw::GLenum errorCode) const
+{
+ if (m_errorCodes.empty() && errorCode == GL_NO_ERROR)
+ return true;
+ else
+ // only this error code listed
+ return m_errorCodes.size() == 1 && m_errorCodes.front().errorCode == errorCode;
+}
+
+void ValidStatusCodes::addErrorCode (glw::GLenum error, const char* description)
+{
+ DE_ASSERT(isErrorCode(error));
+ DE_ASSERT(error != GL_NO_ERROR);
+ addViolation(m_errorCodes, error, description);
+}
+
+void ValidStatusCodes::addFBOErrorStatus (glw::GLenum status, const char* description)
+{
+ DE_ASSERT(isFramebufferStatus(status));
+ DE_ASSERT(status != GL_FRAMEBUFFER_COMPLETE);
+ addViolation(m_errorStatuses, status, description);
+}
+
+void ValidStatusCodes::setAllowComplete (bool b)
+{
+ m_allowComplete = b;
+}
+
+void ValidStatusCodes::logLegalResults (tcu::TestLog& log) const
+{
+ tcu::MessageBuilder msg (&log);
+ std::vector<std::string> validResults;
+
+ for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
+ validResults.push_back(std::string(glu::getErrorName(m_errorCodes[ndx].errorCode)) + " (during FBO initialization)");
+
+ for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
+ validResults.push_back(glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode));
+
+ if (m_allowComplete)
+ validResults.push_back("GL_FRAMEBUFFER_COMPLETE");
+
+ msg << "Expected ";
+ if (validResults.size() > 1)
+ msg << "one of ";
+
+ for (int ndx = 0; ndx < (int)validResults.size(); ++ndx)
+ {
+ const bool last = ((ndx + 1) == (int)validResults.size());
+ const bool secondToLast = ((ndx + 2) == (int)validResults.size());
+
+ msg << validResults[ndx];
+ if (!last)
+ msg << ((secondToLast) ? (" or ") : (", "));
+ }
+
+ msg << "." << TestLog::EndMessage;
+}
+
+void ValidStatusCodes::logRules (tcu::TestLog& log) const
+{
+ const tcu::ScopedLogSection section(log, "Rules", "Active rules");
+
+ for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
+ logRule(log, glu::getErrorName(m_errorCodes[ndx].errorCode), m_errorCodes[ndx].rules);
+
+ for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
+ logRule(log, glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode), m_errorStatuses[ndx].rules);
+
+ if (m_allowComplete)
+ {
+ std::set<std::string> defaultRule;
+ defaultRule.insert("FBO is complete");
+ logRule(log, "GL_FRAMEBUFFER_COMPLETE", defaultRule);
+ }
+}
+
+void ValidStatusCodes::logRule (tcu::TestLog& log, const std::string& ruleName, const std::set<std::string>& rules) const
+{
+ if (!rules.empty())
+ {
+ const tcu::ScopedLogSection section (log, ruleName, ruleName);
+ tcu::MessageBuilder msg (&log);
+
+ msg << "Rules:\n";
+ for (std::set<std::string>::const_iterator it = rules.begin(); it != rules.end(); ++it)
+ msg << "\t * " << *it << "\n";
+ msg << TestLog::EndMessage;
+ }
+}
+
+void ValidStatusCodes::addViolation (std::vector<RuleViolation>& dst, glw::GLenum code, const char* description) const
+{
+ // rule violation already exists?
+ for (int ndx = 0; ndx < (int)dst.size(); ++ndx)
+ {
+ if (dst[ndx].errorCode == code)
+ {
+ dst[ndx].rules.insert(std::string(description));
+ return;
+ }
+ }
+
+ // new violation
+ {
+ RuleViolation violation;
+
+ violation.errorCode = code;
+ violation.rules.insert(std::string(description));
+
+ dst.push_back(violation);
+ }
+}
+
FboBuilder::FboBuilder (GLuint fbo, GLenum target, const glw::Functions& gl)
: m_error (GL_NO_ERROR)
, m_target (target)
diff --git a/modules/glshared/glsFboUtil.hpp b/modules/glshared/glsFboUtil.hpp
index 00887a8..6affa68 100644
--- a/modules/glshared/glsFboUtil.hpp
+++ b/modules/glshared/glsFboUtil.hpp
@@ -44,8 +44,6 @@
namespace gls
{
-// Utilities for standard containers. \todo [2013-12-10 lauri] Move to decpp?
-
//! A pair of iterators to present a range.
//! \note This must be POD to allow static initialization.
//! \todo [2013-12-03 lauri] Move this to decpp?
@@ -76,71 +74,6 @@
T2 second;
};
-template<typename C>
-C intersection(const C& s1, const C& s2)
-{
- C ret;
- std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
- std::insert_iterator<C>(ret, ret.begin()));
- return ret;
-}
-
-// \todo [2013-12-03 lauri] move to decpp?
-template<typename C>
-inline bool isMember (const typename C::key_type& key, const C& container)
-{
- typename C::const_iterator it = container.find(key);
- return (it != container.end());
-}
-
-template <typename M> inline
-const typename M::mapped_type* lookupMaybe (const M& map,
- const typename M::key_type& key)
-{
- typename M::const_iterator it = map.find(key);
- if (it == map.end())
- return DE_NULL;
- return &it->second;
-}
-
-template<typename M> inline
-const typename M::mapped_type& lookupDefault (const M& map,
- const typename M::key_type& key,
- const typename M::mapped_type& fallback)
-{
- const typename M::mapped_type* ptr = lookupMaybe(map, key);
- return ptr == DE_NULL ? fallback : *ptr;
-}
-
-
-template<typename M>
-const typename M::mapped_type& lookup (const M& map,
- const typename M::key_type& key)
-{
- const typename M::mapped_type* ptr = lookupMaybe(map, key);
- if (ptr == DE_NULL)
- throw std::out_of_range("key not found in map");
- return *ptr;
-}
-
-template<typename C>
-inline bool contains (const C& container, const typename C::value_type& item)
-{
- const typename C::const_iterator it = container.find(item);
- return (it != container.end());
-}
-
-
-template<typename M> static inline
-bool insert(const typename M::key_type& key, const typename M::mapped_type& value, M& map)
-{
- typename M::value_type entry(key, value);
- std::pair<typename M::iterator,bool> ret = map.insert(entry);
- return ret.second;
-}
-
-std::vector<std::string> splitString(const std::string& s);
-
namespace FboUtil
{
@@ -163,7 +96,7 @@
//! Type if format is unsized, GL_NONE if sized.
glw::GLenum unsizedType;
- bool operator< (const ImageFormat& other) const
+ bool operator< (const ImageFormat& other) const
{
return (format < other.format ||
(format == other.format && unsizedType < other.unsizedType));
@@ -176,6 +109,8 @@
}
};
+std::ostream& operator<< (std::ostream& stream, const ImageFormat& format);
+
static inline ImageFormat formatKeyInfo(FormatKey key)
{
ImageFormat fmt = { key & 0xffff, key >> 16 };
@@ -205,15 +140,28 @@
class FormatDB
{
public:
- void addFormat (ImageFormat format, FormatFlags flags);
- Formats getFormats (FormatFlags requirements) const;
- FormatFlags getFormatInfo (ImageFormat format,
- FormatFlags fallback) const;
+ void addCoreFormat (ImageFormat format, FormatFlags flags);
+ void addExtensionFormat (ImageFormat format, FormatFlags flags, const std::set<std::string>& requiredExtensions);
+
+ Formats getFormats (FormatFlags requirements) const;
+ bool isKnownFormat (ImageFormat format) const;
+ FormatFlags getFormatInfo (ImageFormat format) const;
+ std::set<std::set<std::string> > getFormatFeatureExtensions (ImageFormat format, FormatFlags requirements) const;
private:
- typedef std::map<ImageFormat, FormatFlags> FormatMap;
+ struct ExtensionInfo
+ {
+ FormatFlags flags;
+ std::set<std::string> requiredExtensions;
- FormatMap m_map;
+ bool operator< (const ExtensionInfo& other) const;
+ };
+
+ typedef std::map<ImageFormat, FormatFlags> FormatMap;
+ typedef std::map<ImageFormat, std::set<ExtensionInfo> > FormatExtensionMap;
+
+ FormatMap m_formatFlags;
+ FormatExtensionMap m_formatExtensions;
};
typedef Pair<FormatFlags, FormatKeys> FormatEntry;
@@ -233,17 +181,22 @@
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);
+// Check support for GL_* and DEQP_* extensions
+bool checkExtensionSupport (const glu::RenderContext& ctx, const std::string& extension);
+
+// 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
{
struct Config
{
- virtual ~Config (void) {};
+ virtual ~Config (void) {};
};
struct Image : public Config
@@ -270,7 +223,7 @@
{
Texture (void) : numLevels(1) {}
- glw::GLint numLevels;
+ glw::GLint numLevels;
};
struct TextureFlat : public Texture
@@ -303,8 +256,8 @@
{
Attachment (void) : target(GL_FRAMEBUFFER), imageName(0) {}
- glw::GLenum target;
- glw::GLuint imageName;
+ glw::GLenum target;
+ glw::GLuint imageName;
//! Returns `true` iff this attachment is "framebuffer attachment
//! complete" when bound to attachment point `attPoint`, and the current
@@ -370,8 +323,6 @@
} // config
-void logFramebufferConfig(const config::Framebuffer& cfg, tcu::TestLog& log);
-
class FboBuilder : public config::Framebuffer
{
public:
@@ -406,27 +357,67 @@
Configs m_configs;
};
-typedef std::set<glw::GLenum> StatusCodes;
+struct ValidStatusCodes
+{
+ ValidStatusCodes (void);
+
+ bool isFBOStatusValid (glw::GLenum fboStatus) const;
+ bool isFBOStatusRequired (glw::GLenum fboStatus) const;
+ bool isErrorCodeValid (glw::GLenum errorCode) const;
+ bool isErrorCodeRequired (glw::GLenum errorCode) const;
+
+ void addErrorCode (glw::GLenum error, const char* description);
+ void addFBOErrorStatus (glw::GLenum status, const char* description);
+ void setAllowComplete (bool);
+
+ void logLegalResults (tcu::TestLog& log) const;
+ void logRules (tcu::TestLog& log) const;
+
+private:
+ struct RuleViolation
+ {
+ glw::GLenum errorCode;
+ std::set<std::string> rules;
+ };
+
+ void logRule (tcu::TestLog& log, const std::string& ruleName, const std::set<std::string>& rules) const;
+ void addViolation (std::vector<RuleViolation>& dst, glw::GLenum code, const char* description) const;
+
+ std::vector<RuleViolation> m_errorCodes; //!< Allowed GL errors, GL_NO_ERROR is not allowed
+ std::vector<RuleViolation> m_errorStatuses; //!< Allowed FBO error statuses, GL_FRAMEBUFFER_COMPLETE is not allowed
+ bool m_allowComplete; //!< true if (GL_NO_ERROR && GL_FRAMEBUFFER_COMPLETE) is allowed
+};
+
+void logFramebufferConfig (const config::Framebuffer& cfg, tcu::TestLog& log);
class Checker
{
public:
- Checker (void) { m_statusCodes.insert(GL_FRAMEBUFFER_COMPLETE); }
- virtual ~Checker (void) {}
- void require (bool condition, glw::GLenum error);
- void canRequire (bool condition, glw::GLenum error);
- StatusCodes getStatusCodes (void) { return m_statusCodes; }
- virtual void check (glw::GLenum attPoint, const config::Attachment& att,
- const config::Image* image) = 0;
-private:
+ Checker (const glu::RenderContext&);
+ virtual ~Checker (void) {}
- StatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus.
+ void addGLError (glw::GLenum error, const char* description);
+ void addPotentialGLError (glw::GLenum error, const char* description);
+ void addFBOStatus (glw::GLenum status, const char* description);
+ void addPotentialFBOStatus (glw::GLenum status, const char* description);
+
+ ValidStatusCodes getStatusCodes (void) { return m_statusCodes; }
+
+ virtual void check (glw::GLenum attPoint,
+ const config::Attachment& att,
+ const config::Image* image) = 0;
+
+protected:
+ const glu::RenderContext& m_renderCtx;
+
+private:
+ ValidStatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus.
};
class CheckerFactory
{
public:
- virtual Checker* createChecker (void) = 0;
+ virtual Checker* createChecker (const glu::RenderContext&) = 0;
};
typedef std::set<glw::GLenum> AttachmentPoints;
@@ -435,14 +426,16 @@
class FboVerifier
{
public:
- FboVerifier (const FormatDB& formats,
- CheckerFactory& factory);
+ FboVerifier (const FormatDB& formats,
+ CheckerFactory& factory,
+ const glu::RenderContext& renderCtx);
- StatusCodes validStatusCodes (const config::Framebuffer& cfg) const;
+ ValidStatusCodes validStatusCodes (const config::Framebuffer& cfg) const;
private:
const FormatDB& m_formats;
CheckerFactory& m_factory;
+ const glu::RenderContext& m_renderCtx;
};
} // FboUtil