/*------------------------------------------------------------------------- * 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