/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL (ES) Module
* -----------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Framebuffer completeness tests.
*//*--------------------------------------------------------------------*/
#include "es2fFboCompletenessTests.hpp"
#include "glsFboCompletenessTests.hpp"
#include "gluObjectWrapper.hpp"
using namespace glw;
using deqp::gls::Range;
using namespace deqp::gls::FboUtil;
using namespace deqp::gls::FboUtil::config;
namespace fboc = deqp::gls::fboc;
typedef tcu::TestCase::IterateResult IterateResult;
namespace deqp
{
namespace gles2
{
namespace Functional
{
static const FormatKey s_es2ColorRenderables[] =
{
GL_RGBA4, GL_RGB5_A1, GL_RGB565,
};
// GLES2 does not strictly allow these, but this seems to be a bug in the
// specification. For now, let's assume the unsized formats corresponding to
// the color-renderable sized formats are allowed.
// See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=7333
static const FormatKey s_es2UnsizedColorRenderables[] =
{
GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4),
GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1),
GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_SHORT_5_6_5)
};
static const FormatKey s_es2DepthRenderables[] =
{
GL_DEPTH_COMPONENT16,
};
static const FormatKey s_es2StencilRenderables[] =
{
GL_STENCIL_INDEX8,
};
static const FormatEntry s_es2Formats[] =
{
{ COLOR_RENDERABLE | TEXTURE_VALID,
GLS_ARRAY_RANGE(s_es2UnsizedColorRenderables) },
{ REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
GLS_ARRAY_RANGE(s_es2ColorRenderables) },
{ REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID,
GLS_ARRAY_RANGE(s_es2DepthRenderables) },
{ REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID,
GLS_ARRAY_RANGE(s_es2StencilRenderables) },
};
// We have here only the extensions that are redundant in vanilla GLES3. Those
// that are applicable both to GLES2 and GLES3 are in glsFboCompletenessTests.cpp.
// GL_OES_texture_float
static const FormatKey s_oesTextureFloatFormats[] =
{
GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_FLOAT),
GLS_UNSIZED_FORMATKEY(GL_RGB, GL_FLOAT),
};
// GL_OES_texture_half_float
static const FormatKey s_oesTextureHalfFloatFormats[] =
{
GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_HALF_FLOAT_OES),
GLS_UNSIZED_FORMATKEY(GL_RGB, GL_HALF_FLOAT_OES),
};
// GL_EXT_sRGB_write_control
static const FormatKey s_extSrgbWriteControlFormats[] =
{
GL_SRGB8_ALPHA8
};
// DEQP_gles3_core_no_extension_features
static const FormatKey s_es3NoExtRboFormats[] =
{
GL_RGB10_A2,
GL_SRGB8_ALPHA8,
};
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,
GL_RGB8,
GL_RGBA4,
GL_RGB5_A1,
GL_RGBA8,
GL_RGB10_A2,
GL_RGB565,
GL_SRGB8_ALPHA8,
};
// 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,
};
// DEQP_gles3_core_changed_features
static const FormatKey s_es3NoExtDepthRenderable[] =
{
GL_DEPTH_COMPONENT16,
GL_DEPTH_COMPONENT24,
GL_DEPTH24_STENCIL8,
};
static const FormatKey s_es3NoExtStencilRenderable[] =
{
GL_DEPTH24_STENCIL8,
};
static const FormatExtEntry s_es2ExtFormats[] =
{
// The extension does not specify these to be color-renderable.
{
"GL_OES_texture_float",
(deUint32)TEXTURE_VALID,
GLS_ARRAY_RANGE(s_oesTextureFloatFormats)
},
{
"GL_OES_texture_half_float",
(deUint32)TEXTURE_VALID,
GLS_ARRAY_RANGE(s_oesTextureHalfFloatFormats)
},
// GL_EXT_sRGB_write_control makes SRGB8_ALPHA8 color-renderable
{
"GL_EXT_sRGB_write_control",
(deUint32)(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",
(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID),
GLS_ARRAY_RANGE(s_es3NoExtRboFormats)
},
{
"DEQP_gles3_core_compatible",
(deUint32)TEXTURE_VALID,
GLS_ARRAY_RANGE(s_es3NoExtTextureFormats)
},
{
"DEQP_gles3_core_compatible",
(deUint32)(REQUIRED_RENDERABLE | TEXTURE_VALID | COLOR_RENDERABLE | RENDERBUFFER_VALID),
GLS_ARRAY_RANGE(s_es3NoExtTextureColorRenderableFormats)
},
{
"DEQP_gles3_core_compatible GL_EXT_color_buffer_float",
(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID),
GLS_ARRAY_RANGE(s_es3NoExtExtColorBufferFloatFormats)
},
{
"DEQP_gles3_core_compatible GL_OES_texture_stencil8",
(deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID),
GLS_ARRAY_RANGE(s_es3NoExtOesTextureStencil8Formats)
},
{
"DEQP_gles3_core_compatible GL_OES_texture_half_float GL_EXT_color_buffer_half_float",
(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE),
GLS_ARRAY_RANGE(s_oesTextureHalfFloatFormats)
},
{
"DEQP_gles3_core_compatible",
(deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID),
GLS_ARRAY_RANGE(s_es3NoExtDepthRenderable)
},
{
"DEQP_gles3_core_compatible",
(deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID),
GLS_ARRAY_RANGE(s_es3NoExtStencilRenderable)
},
};
class ES2Checker : public Checker
{
public:
ES2Checker (const glu::RenderContext& ctx);
void check (GLenum attPoint, const Attachment& att,
const Image* image);
private:
GLsizei m_width; //< The common width of images
GLsizei m_height; //< The common height of images
};
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);
// GLES2: "All attached images have the same width and height."
if (m_width == -1)
{
m_width = image->width;
m_height = image->height;
}
else if (image->width != m_width || image->height != m_height)
{
// 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
// formats of the images attached to a framebuffer object are not
// supported by the implementation, then the framebuffer is not complete
// under the clause labeled FRAMEBUFFER_UNSUPPORTED."
//
// Hence it is _always_ allowed to report FRAMEBUFFER_UNSUPPORTED.
addPotentialFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Particular format combinations need not to be supported");
}
struct FormatCombination
{
GLenum colorKind;
ImageFormat colorFmt;
GLenum depthKind;
ImageFormat depthFmt;
GLenum stencilKind;
ImageFormat stencilFmt;
};
class SupportedCombinationTest : public fboc::TestBase
{
public:
SupportedCombinationTest (fboc::Context& ctx,
const char* name, const char* desc)
: TestBase (ctx, name, desc) {}
IterateResult iterate (void);
bool tryCombination (const FormatCombination& comb);
GLenum formatKind (ImageFormat fmt);
};
bool SupportedCombinationTest::tryCombination (const FormatCombination& comb)
{
glu::Framebuffer fbo(m_ctx.getRenderContext());
FboBuilder builder(*fbo, GL_FRAMEBUFFER, fboc::gl(*this));
attachTargetToNew(GL_COLOR_ATTACHMENT0, comb.colorKind, comb.colorFmt,
64, 64, builder);
attachTargetToNew(GL_DEPTH_ATTACHMENT, comb.depthKind, comb.depthFmt,
64, 64, builder);
attachTargetToNew(GL_STENCIL_ATTACHMENT, comb.stencilKind, comb.stencilFmt,
64, 64, builder);
const GLenum glStatus = fboc::gl(*this).checkFramebufferStatus(GL_FRAMEBUFFER);
return (glStatus == GL_FRAMEBUFFER_COMPLETE);
}
GLenum SupportedCombinationTest::formatKind (ImageFormat fmt)
{
if (fmt.format == GL_NONE)
return GL_NONE;
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));
return rbo ? GL_RENDERBUFFER : GL_TEXTURE;
}
IterateResult SupportedCombinationTest::iterate (void)
{
const FormatDB& db = m_ctx.getCoreFormats();
const ImageFormat none = ImageFormat::none();
Formats colorFmts = db.getFormats(COLOR_RENDERABLE);
Formats depthFmts = db.getFormats(DEPTH_RENDERABLE);
Formats stencilFmts = db.getFormats(STENCIL_RENDERABLE);
FormatCombination comb;
bool succ = false;
colorFmts.insert(none);
depthFmts.insert(none);
stencilFmts.insert(none);
for (Formats::const_iterator col = colorFmts.begin(); col != colorFmts.end(); col++)
{
comb.colorFmt = *col;
comb.colorKind = formatKind(*col);
for (Formats::const_iterator dep = depthFmts.begin(); dep != depthFmts.end(); dep++)
{
comb.depthFmt = *dep;
comb.depthKind = formatKind(*dep);
for (Formats::const_iterator stc = stencilFmts.begin();
stc != stencilFmts.end(); stc++)
{
comb.stencilFmt = *stc;
comb.stencilKind = formatKind(*stc);
succ = tryCombination(comb);
if (succ)
break;
}
}
}
if (succ)
pass();
else
fail("No supported format combination found");
return STOP;
}
class ES2CheckerFactory : public CheckerFactory
{
public:
Checker* createChecker (const glu::RenderContext& ctx) { return new ES2Checker(ctx); }
};
class TestGroup : public TestCaseGroup
{
public:
TestGroup (Context& ctx);
void init (void);
private:
ES2CheckerFactory m_checkerFactory;
fboc::Context m_fboc;
};
TestGroup::TestGroup (Context& ctx)
: TestCaseGroup (ctx, "completeness", "Completeness tests")
, m_checkerFactory ()
, m_fboc (ctx.getTestContext(), ctx.getRenderContext(), m_checkerFactory)
{
const FormatEntries stdRange = GLS_ARRAY_RANGE(s_es2Formats);
const FormatExtEntries extRange = GLS_ARRAY_RANGE(s_es2ExtFormats);
m_fboc.addFormats(stdRange);
m_fboc.addExtFormats(extRange);
m_fboc.setHaveMulticolorAtts(
ctx.getContextInfo().isExtensionSupported("GL_NV_fbo_color_attachments"));
}
void TestGroup::init (void)
{
tcu::TestCaseGroup* attCombTests = m_fboc.createAttachmentTests();
addChild(m_fboc.createRenderableTests());
attCombTests->addChild(new SupportedCombinationTest(
m_fboc,
"exists_supported",
"Test for existence of a supported combination of formats"));
addChild(attCombTests);
addChild(m_fboc.createSizeTests());
}
tcu::TestCaseGroup* createFboCompletenessTests (Context& context)
{
return new TestGroup(context);
}
} // Functional
} // gles2
} // deqp