/*------------------------------------------------------------------------- * 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 "glsFboCompletenessTests.hpp" #include "gluStrUtil.hpp" #include "gluObjectWrapper.hpp" #include "deStringUtil.hpp" #include <cctype> #include <iterator> #include <algorithm> using namespace glw; using glu::RenderContext; using glu::getFramebufferStatusName; using glu::getTextureFormatName; using glu::getTypeName; using glu::getErrorName; using glu::Framebuffer; using tcu::TestCase; using tcu::TestCaseGroup; using tcu::TestLog; using tcu::MessageBuilder; 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; namespace deqp { namespace gls { namespace fboc { namespace details { // The following extensions are applicable both to ES2 and ES3. // GL_OES_depth_texture static const FormatKey s_oesDepthTextureFormats[] = { GLS_UNSIZED_FORMATKEY(GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT), GLS_UNSIZED_FORMATKEY(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT), }; // GL_OES_packed_depth_stencil static const FormatKey s_oesPackedDepthStencilSizedFormats[] = { GL_DEPTH24_STENCIL8, }; static const FormatKey s_oesPackedDepthStencilTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8), }; // GL_OES_required_internalformat static const FormatKey s_oesRequiredInternalFormatColorFormats[] = { // Same as ES2 RBO formats, plus RGBA8 (even without OES_rgb8_rgba8) GL_RGB5_A1, GL_RGBA8, GL_RGBA4, GL_RGB565 }; static const FormatKey s_oesRequiredInternalFormatDepthFormats[] = { GL_DEPTH_COMPONENT16, }; // GL_EXT_color_buffer_half_float static const FormatKey s_extColorBufferHalfFloatFormats[] = { GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F, }; static const FormatKey s_oesDepth24SizedFormats[] = { GL_DEPTH_COMPONENT24 }; static const FormatKey s_oesDepth32SizedFormats[] = { GL_DEPTH_COMPONENT32 }; static const FormatKey s_oesRgb8Rgba8RboFormats[] = { GL_RGB8, GL_RGBA8, }; static const FormatKey s_oesRequiredInternalFormatRgb8ColorFormat[] = { GL_RGB8, }; static const FormatKey s_extTextureType2101010RevFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV), GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV), }; static const FormatKey s_oesRequiredInternalFormat10bitColorFormats[] = { GL_RGB10_A2, GL_RGB10, }; static const FormatKey s_extTextureRgRboFormats[] = { GL_R8, GL_RG8, }; static const FormatKey s_extTextureRgTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RED, GL_UNSIGNED_BYTE), GLS_UNSIZED_FORMATKEY(GL_RG, GL_UNSIGNED_BYTE), }; static const FormatKey s_extTextureRgFloatTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RED, GL_FLOAT), GLS_UNSIZED_FORMATKEY(GL_RG, GL_FLOAT), }; static const FormatKey s_extTextureRgHalfFloatTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RED, GL_HALF_FLOAT_OES), GLS_UNSIZED_FORMATKEY(GL_RG, GL_HALF_FLOAT_OES), }; static const FormatKey s_nvPackedFloatRboFormats[] = { GL_R11F_G11F_B10F, }; static const FormatKey s_nvPackedFloatTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV), }; static const FormatKey s_extSrgbRboFormats[] = { GL_SRGB8_ALPHA8, }; static const FormatKey s_extSrgbRenderableTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_SRGB_ALPHA, GL_UNSIGNED_BYTE), }; static const FormatKey s_extSrgbNonRenderableTexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_SRGB, GL_UNSIGNED_BYTE), GL_SRGB8, }; static const FormatKey s_nvSrgbFormatsRboFormats[] = { GL_SRGB8, }; static const FormatKey s_nvSrgbFormatsTextureFormats[] = { GL_SRGB8, // The extension does not actually require any unsized format // to be renderable. However, the renderablility of unsized // SRGB,UBYTE internalformat-type pair is implied. GLS_UNSIZED_FORMATKEY(GL_SRGB, GL_UNSIGNED_BYTE), }; static const FormatKey s_oesRgb8Rgba8TexFormats[] = { GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_BYTE), GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_BYTE), }; static const FormatKey s_extTextureSRGBR8Formats[] = { GL_SR8_EXT, }; static const FormatKey s_extTextureSRGBRG8Formats[] = { GL_SRG8_EXT, }; static const FormatExtEntry s_esExtFormats[] = { { "GL_OES_depth_texture", (deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesDepthTextureFormats), }, { "GL_OES_packed_depth_stencil", (deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_oesPackedDepthStencilSizedFormats) }, { "GL_OES_packed_depth_stencil GL_OES_required_internalformat", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_oesPackedDepthStencilSizedFormats) }, { "GL_OES_packed_depth_stencil GL_OES_depth_texture", (deUint32)(DEPTH_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesPackedDepthStencilTexFormats) }, // The ANGLE extension incorporates GL_OES_depth_texture/GL_OES_packed_depth_stencil. { "GL_ANGLE_depth_texture", (deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesDepthTextureFormats), }, // \todo [2013-12-10 lauri] Find out if OES_texture_half_float is really a // requirement on ES3 also. Or is color_buffer_half_float applicatble at // all on ES3, since there's also EXT_color_buffer_float? { "GL_OES_texture_half_float GL_EXT_color_buffer_half_float", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_extColorBufferHalfFloatFormats) }, // OES_required_internalformat doesn't actually specify that these are renderable, // since it was written against ES 1.1. { "GL_OES_required_internalformat", // Allow but don't require RGBA8 to be color-renderable if // OES_rgb8_rgba8 is not present. (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesRequiredInternalFormatColorFormats) }, { "GL_OES_required_internalformat", (deUint32)(DEPTH_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesRequiredInternalFormatDepthFormats) }, { "GL_EXT_texture_rg", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_extTextureRgRboFormats) }, // These are not specified to be color-renderable, but the wording is // exactly as ambiguous as the wording in the ES2 spec. { "GL_EXT_texture_rg", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_extTextureRgTexFormats) }, { "GL_EXT_texture_rg GL_OES_texture_float", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_extTextureRgFloatTexFormats) }, { "GL_EXT_texture_rg GL_OES_texture_half_float", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_extTextureRgHalfFloatTexFormats) }, { "GL_NV_packed_float", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_nvPackedFloatTexFormats) }, { "GL_NV_packed_float GL_EXT_color_buffer_half_float", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_nvPackedFloatRboFormats) }, { "GL_EXT_sRGB", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_extSrgbRenderableTexFormats) }, { "GL_EXT_sRGB", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_extSrgbNonRenderableTexFormats) }, { "GL_EXT_sRGB", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_extSrgbRboFormats) }, { "GL_NV_sRGB_formats", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_nvSrgbFormatsRboFormats) }, { "GL_NV_sRGB_formats", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_nvSrgbFormatsTextureFormats) }, // In Khronos bug 7333 discussion, the consensus is that these texture // formats, at least, should be color-renderable. Still, that cannot be // found in any extension specs, so only allow it, not require it. { "GL_OES_rgb8_rgba8", (deUint32)(COLOR_RENDERABLE | TEXTURE_VALID), GLS_ARRAY_RANGE(s_oesRgb8Rgba8TexFormats) }, { "GL_OES_rgb8_rgba8", (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_oesRgb8Rgba8RboFormats) }, { "GL_OES_rgb8_rgba8 GL_OES_required_internalformat", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_oesRequiredInternalFormatRgb8ColorFormat) }, // The depth-renderability of the depth RBO formats is not explicitly // spelled out, but all renderbuffer formats are meant to be renderable. { "GL_OES_depth24", (deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_oesDepth24SizedFormats) }, { "GL_OES_depth24 GL_OES_required_internalformat GL_OES_depth_texture", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_oesDepth24SizedFormats) }, { "GL_OES_depth32", (deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID), GLS_ARRAY_RANGE(s_oesDepth32SizedFormats) }, { "GL_OES_depth32 GL_OES_required_internalformat GL_OES_depth_texture", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_oesDepth32SizedFormats) }, { "GL_EXT_texture_type_2_10_10_10_REV", (deUint32)TEXTURE_VALID, // explicitly unrenderable GLS_ARRAY_RANGE(s_extTextureType2101010RevFormats) }, { "GL_EXT_texture_type_2_10_10_10_REV GL_OES_required_internalformat", (deUint32)TEXTURE_VALID, // explicitly unrenderable GLS_ARRAY_RANGE(s_oesRequiredInternalFormat10bitColorFormats) }, { "GL_EXT_texture_sRGB_R8", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_extTextureSRGBR8Formats) }, { "GL_EXT_texture_sRGB_RG8", (deUint32)TEXTURE_VALID, GLS_ARRAY_RANGE(s_extTextureSRGBRG8Formats) }, }; Context::Context (TestContext& testCtx, RenderContext& renderCtx, CheckerFactory& factory) : m_testCtx (testCtx) , m_renderCtx (renderCtx) , m_verifier (m_ctxFormats, factory, renderCtx) , m_haveMultiColorAtts (false) { FormatExtEntries extRange = GLS_ARRAY_RANGE(s_esExtFormats); addExtFormats(extRange); } void Context::addFormats (FormatEntries fmtRange) { FboUtil::addFormats(m_coreFormats, fmtRange); FboUtil::addFormats(m_ctxFormats, fmtRange); FboUtil::addFormats(m_allFormats, fmtRange); } void Context::addExtFormats (FormatExtEntries extRange) { FboUtil::addExtFormats(m_ctxFormats, extRange, &m_renderCtx); FboUtil::addExtFormats(m_allFormats, extRange, DE_NULL); } void TestBase::pass (void) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } void TestBase::qualityWarning (const char* msg) { m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, msg); } void TestBase::fail (const char* msg) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, msg); } 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 ValidStatusCodes reference = m_ctx.getVerifier().validStatusCodes(builder); const GLenum errorCode = builder.getError(); 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. if (errorCode != GL_NO_ERROR) { m_testCtx.getLog() << TestLog::Message << "Received " << glu::getErrorStr(errorCode) << " (during FBO initialization)." << TestLog::EndMessage; 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 fail("Got wrong error code"); } else { 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; } IterateResult TestBase::build (FboBuilder& builder) { DE_UNREF(builder); return STOP; } ImageFormat TestBase::getDefaultFormat (GLenum attPoint, GLenum bufType) const { if (bufType == GL_NONE) { return ImageFormat::none(); } // Prefer a standard format, if there is one, but if not, use a format // provided by an extension. Formats formats = m_ctx.getCoreFormats().getFormats(formatFlag(attPoint) | formatFlag(bufType)); Formats::const_iterator it = formats.begin(); if (it == formats.end()) { formats = m_ctx.getCtxFormats().getFormats(formatFlag(attPoint) | formatFlag(bufType)); it = formats.begin(); } if (it == formats.end()) throw tcu::NotSupportedError("Unsupported attachment kind for attachment point", "", __FILE__, __LINE__); return *it; }; Image* makeImage (GLenum bufType, ImageFormat format, GLsizei width, GLsizei height, FboBuilder& builder) { Image* image = DE_NULL; switch (bufType) { case GL_NONE: return DE_NULL; case GL_RENDERBUFFER: image = &builder.makeConfig<Renderbuffer>(); break; case GL_TEXTURE: image = &builder.makeConfig<Texture2D>(); break; default: DE_FATAL("Impossible case"); } image->internalFormat = format; image->width = width; image->height = height; return image; } Attachment* makeAttachment (GLenum bufType, ImageFormat format, GLsizei width, GLsizei height, FboBuilder& builder) { Image* const imgCfg = makeImage (bufType, format, width, height, builder); Attachment* att = DE_NULL; GLuint img = 0; if (Renderbuffer* rboCfg = dynamic_cast<Renderbuffer*>(imgCfg)) { img = builder.glCreateRbo(*rboCfg); att = &builder.makeConfig<RenderbufferAttachment>(); } else if (Texture2D* texCfg = dynamic_cast<Texture2D*>(imgCfg)) { img = builder.glCreateTexture(*texCfg); TextureFlatAttachment& texAtt = builder.makeConfig<TextureFlatAttachment>(); texAtt.texTarget = GL_TEXTURE_2D; att = &texAtt; } else { DE_ASSERT(imgCfg == DE_NULL); return DE_NULL; } att->imageName = img; return att; } void TestBase::attachTargetToNew (GLenum target, GLenum bufType, ImageFormat format, GLsizei width, GLsizei height, FboBuilder& builder) { ImageFormat imgFmt = format; if (imgFmt.format == GL_NONE) imgFmt = getDefaultFormat(target, bufType); const Attachment* const att = makeAttachment(bufType, imgFmt, width, height, builder); builder.glAttach(target, att); } static string formatName (ImageFormat format) { const string s = getTextureFormatName(format.format); const string fmtStr = toLower(s.substr(3)); if (format.unsizedType != GL_NONE) { const string typeStr = getTypeName(format.unsizedType); return fmtStr + "_" + toLower(typeStr.substr(3)); } return fmtStr; } static string formatDesc (ImageFormat format) { const string fmtStr = getTextureFormatName(format.format); if (format.unsizedType != GL_NONE) { const string typeStr = getTypeName(format.unsizedType); return fmtStr + " with type " + typeStr; } return fmtStr; } struct RenderableParams { GLenum attPoint; GLenum bufType; ImageFormat format; static string getName (const RenderableParams& params) { return formatName(params.format); } static string getDescription (const RenderableParams& params) { return formatDesc(params.format); } }; class RenderableTest : public ParamTest<RenderableParams> { public: RenderableTest (Context& group, const Params& params) : ParamTest<RenderableParams> (group, params) {} IterateResult build (FboBuilder& builder); }; IterateResult RenderableTest::build (FboBuilder& builder) { attachTargetToNew(m_params.attPoint, m_params.bufType, m_params.format, 64, 64, builder); return STOP; } string attTypeName (GLenum bufType) { switch (bufType) { case GL_NONE: return "none"; case GL_RENDERBUFFER: return "rbo"; case GL_TEXTURE: return "tex"; default: DE_FATAL("Impossible case"); } return ""; // Shut up compiler } struct AttachmentParams { GLenum color0Kind; GLenum colornKind; GLenum depthKind; GLenum stencilKind; static string getName (const AttachmentParams& params); static string getDescription (const AttachmentParams& params) { return getName(params); } }; string AttachmentParams::getName (const AttachmentParams& params) { return (attTypeName(params.color0Kind) + "_" + attTypeName(params.colornKind) + "_" + attTypeName(params.depthKind) + "_" + attTypeName(params.stencilKind)); } //! Test for combinations of different kinds of attachments class AttachmentTest : public ParamTest<AttachmentParams> { public: AttachmentTest (Context& group, Params& params) : ParamTest<AttachmentParams> (group, params) {} protected: IterateResult build (FboBuilder& builder); void makeDepthAndStencil (FboBuilder& builder); }; void AttachmentTest::makeDepthAndStencil (FboBuilder& builder) { if (m_params.stencilKind == m_params.depthKind) { // If there is a common stencil+depth -format, try to use a common // image for both attachments. const FormatFlags flags = DEPTH_RENDERABLE | STENCIL_RENDERABLE | formatFlag(m_params.stencilKind); const Formats& formats = m_ctx.getCoreFormats().getFormats(flags); Formats::const_iterator it = formats.begin(); if (it != formats.end()) { const ImageFormat format = *it; Attachment* att = makeAttachment(m_params.depthKind, format, 64, 64, builder); builder.glAttach(GL_DEPTH_ATTACHMENT, att); builder.glAttach(GL_STENCIL_ATTACHMENT, att); return; } } // Either the kinds were separate, or a suitable format was not found. // Create separate images. attachTargetToNew(GL_STENCIL_ATTACHMENT, m_params.stencilKind, ImageFormat::none(), 64, 64, builder); attachTargetToNew(GL_DEPTH_ATTACHMENT, m_params.depthKind, ImageFormat::none(), 64, 64, builder); } IterateResult AttachmentTest::build (FboBuilder& builder) { attachTargetToNew(GL_COLOR_ATTACHMENT0, m_params.color0Kind, ImageFormat::none(), 64, 64, builder); if (m_params.colornKind != GL_NONE) { TCU_CHECK_AND_THROW(NotSupportedError, m_ctx.haveMultiColorAtts(), "Multiple attachments not supported"); GLint maxAttachments = 1; gl(*this).getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachments); GLU_EXPECT_NO_ERROR( gl(*this).getError(), "Couldn't read GL_MAX_COLOR_ATTACHMENTS"); for (int i = 1; i < maxAttachments; i++) { attachTargetToNew(GL_COLOR_ATTACHMENT0 + i, m_params.colornKind, ImageFormat::none(), 64, 64, builder); } } makeDepthAndStencil(builder); return STOP; } class EmptyImageTest : public TestBase { public: EmptyImageTest (Context& group, const char* name, const char* desc) : TestBase (group, name, desc) {} IterateResult build (FboBuilder& builder); }; IterateResult EmptyImageTest::build (FboBuilder& builder) { attachTargetToNew(GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ImageFormat::none(), 0, 0, builder); return STOP; } class DistinctSizeTest : public TestBase { public: DistinctSizeTest (Context& group, const char* name, const char* desc) : TestBase (group, name, desc) {} IterateResult build (FboBuilder& builder); }; IterateResult DistinctSizeTest::build (FboBuilder& builder) { attachTargetToNew(GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ImageFormat::none(), 64, 64, builder); attachTargetToNew(GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ImageFormat::none(), 128, 128, builder); return STOP; } TestCaseGroup* Context::createRenderableTests (void) { TestCaseGroup* const renderableTests = new TestCaseGroup( m_testCtx, "renderable", "Tests for support of renderable image formats"); TestCaseGroup* const rbRenderableTests = new TestCaseGroup( m_testCtx, "renderbuffer", "Tests for renderbuffer formats"); TestCaseGroup* const texRenderableTests = new TestCaseGroup( m_testCtx, "texture", "Tests for texture formats"); static const struct AttPoint { GLenum attPoint; const char* name; const char* desc; } attPoints[] = { { GL_COLOR_ATTACHMENT0, "color0", "Tests for color attachments" }, { GL_STENCIL_ATTACHMENT, "stencil", "Tests for stencil attachments" }, { GL_DEPTH_ATTACHMENT, "depth", "Tests for depth attachments" }, }; // At each attachment point, iterate through all the possible formats to // detect both false positives and false negatives. 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++) { TestCaseGroup* const rbAttTests = new TestCaseGroup(m_testCtx, it->name, it->desc); TestCaseGroup* const texAttTests = new TestCaseGroup(m_testCtx, it->name, it->desc); for (Formats::const_iterator it2 = rboFmts.begin(); it2 != rboFmts.end(); it2++) { const RenderableParams params = { it->attPoint, GL_RENDERBUFFER, *it2 }; rbAttTests->addChild(new RenderableTest(*this, params)); } rbRenderableTests->addChild(rbAttTests); for (Formats::const_iterator it2 = texFmts.begin(); it2 != texFmts.end(); it2++) { const RenderableParams params = { it->attPoint, GL_TEXTURE, *it2 }; texAttTests->addChild(new RenderableTest(*this, params)); } texRenderableTests->addChild(texAttTests); } renderableTests->addChild(rbRenderableTests); renderableTests->addChild(texRenderableTests); return renderableTests; } TestCaseGroup* Context::createAttachmentTests (void) { TestCaseGroup* const attCombTests = new TestCaseGroup( m_testCtx, "attachment_combinations", "Tests for attachment combinations"); static const GLenum s_bufTypes[] = { GL_NONE, GL_RENDERBUFFER, GL_TEXTURE }; static const Range<GLenum> s_kinds = GLS_ARRAY_RANGE(s_bufTypes); for (const GLenum* col0 = s_kinds.begin(); col0 != s_kinds.end(); ++col0) for (const GLenum* coln = s_kinds.begin(); coln != s_kinds.end(); ++coln) for (const GLenum* dep = s_kinds.begin(); dep != s_kinds.end(); ++dep) for (const GLenum* stc = s_kinds.begin(); stc != s_kinds.end(); ++stc) { AttachmentParams params = { *col0, *coln, *dep, *stc }; attCombTests->addChild(new AttachmentTest(*this, params)); } return attCombTests; } TestCaseGroup* Context::createSizeTests (void) { TestCaseGroup* const sizeTests = new TestCaseGroup( m_testCtx, "size", "Tests for attachment sizes"); sizeTests->addChild(new EmptyImageTest( *this, "zero", "Test for zero-sized image attachment")); sizeTests->addChild(new DistinctSizeTest( *this, "distinct", "Test for attachments with different sizes")); return sizeTests; } } // details } // fboc } // gls } // deqp