#ifndef _GLSFBOUTIL_HPP #define _GLSFBOUTIL_HPP /*------------------------------------------------------------------------- * 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 Utilities for framebuffer objects. *//*--------------------------------------------------------------------*/ #include "gluRenderContext.hpp" #include "gluContextInfo.hpp" #include "glwDefs.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "gluTextureUtil.hpp" #include "tcuTestLog.hpp" #include "tcuDefs.hpp" #include #include #include #include #include namespace deqp { namespace gls { //! 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? template struct Range { typedef const T *const_iterator; const T *m_begin; const T *m_end; const T *begin(void) const { return m_begin; } const T *end(void) const { return m_end; } }; #define GLS_ARRAY_RANGE(ARR) \ { \ DE_ARRAY_BEGIN(ARR), DE_ARRAY_END(ARR) \ } #define GLS_NULL_RANGE \ { \ DE_NULL, DE_NULL \ } //! A pair type that, unlike stl::pair, is POD so it can be statically initialized. template struct Pair { typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; }; namespace FboUtil { //! Configurations for framebuffer objects and their attachments. class FboVerifier; class FboBuilder; typedef uint32_t FormatKey; #define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) (uint32_t(TYPE) << 16 | uint32_t(FORMAT)) typedef Range FormatKeys; struct ImageFormat { glw::GLenum format; //! Type if format is unsized, GL_NONE if sized. glw::GLenum unsizedType; bool operator<(const ImageFormat &other) const { return (format < other.format || (format == other.format && unsizedType < other.unsizedType)); } static ImageFormat none(void) { ImageFormat fmt = {GL_NONE, GL_NONE}; return fmt; } }; std::ostream &operator<<(std::ostream &stream, const ImageFormat &format); static inline ImageFormat formatKeyInfo(FormatKey key) { ImageFormat fmt = {key & 0xffff, key >> 16}; return fmt; } enum FormatFlags { ANY_FORMAT = 0, COLOR_RENDERABLE = 1 << 0, DEPTH_RENDERABLE = 1 << 1, STENCIL_RENDERABLE = 1 << 2, RENDERBUFFER_VALID = 1 << 3, TEXTURE_VALID = 1 << 4, REQUIRED_RENDERABLE = 1 << 5, //< Without this, renderability is allowed, not required. }; static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2) { return FormatFlags(uint32_t(f1) | uint32_t(f2)); } FormatFlags formatFlag(glw::GLenum context); typedef std::set Formats; class FormatDB { public: void addCoreFormat(ImageFormat format, FormatFlags flags); void addExtensionFormat(ImageFormat format, FormatFlags flags, const std::set &requiredExtensions); Formats getFormats(FormatFlags requirements) const; bool isKnownFormat(ImageFormat format) const; FormatFlags getFormatInfo(ImageFormat format) const; std::set> getFormatFeatureExtensions(ImageFormat format, FormatFlags requirements) const; private: struct ExtensionInfo { FormatFlags flags; std::set requiredExtensions; bool operator<(const ExtensionInfo &other) const; }; typedef std::map FormatMap; typedef std::map> FormatExtensionMap; FormatMap m_formatFlags; FormatExtensionMap m_formatExtensions; }; typedef Pair FormatEntry; typedef Range FormatEntries; // \todo [2013-12-20 lauri] It turns out that format properties in extensions // are actually far too fine-grained for this bundling to be reasonable, // especially given the syntactic cumbersomeness of static arrays. It's better // to list each entry separately. struct FormatExtEntry { const char *extensions; uint32_t flags; Range formats; }; typedef Range FormatExtEntries; // 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) { } }; struct Image : public Config { ImageFormat internalFormat; glw::GLsizei width; glw::GLsizei height; protected: Image(void) : internalFormat(ImageFormat::none()), width(0), height(0) { } }; struct Renderbuffer : public Image { Renderbuffer(void) : numSamples(0) { } glw::GLsizei numSamples; }; struct Texture : public Image { Texture(void) : numLevels(1) { } glw::GLint numLevels; }; struct TextureFlat : public Texture { }; struct Texture2D : public TextureFlat { }; struct TextureCubeMap : public TextureFlat { }; struct TextureLayered : public Texture { TextureLayered(void) : numLayers(1) { } glw::GLsizei numLayers; }; struct Texture3D : public TextureLayered { }; struct Texture2DArray : public TextureLayered { }; struct Attachment : public Config { Attachment(void) : target(GL_FRAMEBUFFER), imageName(0) { } glw::GLenum target; glw::GLuint imageName; //! Returns `true` iff this attachment is "framebuffer attachment //! complete" when bound to attachment point `attPoint`, and the current //! image with name `imageName` is `image`, using `vfr` to check format //! renderability. bool isComplete(glw::GLenum attPoint, const Image *image, const FboVerifier &vfr) const; }; struct RenderbufferAttachment : public Attachment { RenderbufferAttachment(void) : renderbufferTarget(GL_RENDERBUFFER) { } glw::GLenum renderbufferTarget; }; struct TextureAttachment : public Attachment { TextureAttachment(void) : level(0) { } glw::GLint level; }; struct TextureFlatAttachment : public TextureAttachment { TextureFlatAttachment(void) : texTarget(GL_NONE) { } glw::GLenum texTarget; }; struct TextureLayerAttachment : public TextureAttachment { TextureLayerAttachment(void) : layer(0) { } glw::GLsizei layer; }; glw::GLenum attachmentType(const Attachment &att); glw::GLsizei imageNumSamples(const Image &img); //! Mapping from attachment points to attachment configurations. typedef std::map AttachmentMap; //! Mapping from object names to texture configurations. typedef std::map TextureMap; //! Mapping from object names to renderbuffer configurations. typedef std::map RboMap; //! A framebuffer configuration. struct Framebuffer { AttachmentMap attachments; TextureMap textures; RboMap rbos; void attach(glw::GLenum attPoint, const Attachment *att); void setTexture(glw::GLuint texName, const Texture &texCfg); void setRbo(glw::GLuint rbName, const Renderbuffer &rbCfg); const Image *getImage(glw::GLenum type, glw::GLuint imgName) const; }; } // namespace config class FboBuilder : public config::Framebuffer { public: void glAttach(glw::GLenum attPoint, const config::Attachment *att); glw::GLuint glCreateTexture(const config::Texture &texCfg); glw::GLuint glCreateRbo(const config::Renderbuffer &rbCfg); FboBuilder(glw::GLuint fbo, glw::GLenum target, const glw::Functions &gl); ~FboBuilder(void); glw::GLenum getError(void) { return m_error; } //! Allocate a new configuration of type `Config` (which must be a //! subclass of `config::Config`), and return a referenc to it. The newly //! allocated object will be freed when this builder object is destroyed. template Config &makeConfig(void) { Config *cfg = new Config(); m_configs.insert(cfg); return *cfg; } private: typedef std::set Configs; void checkError(void); glw::GLenum m_error; //< The first GL error encountered. glw::GLenum m_target; const glw::Functions &m_gl; Configs m_configs; }; 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 rules; }; void logRule(tcu::TestLog &log, const std::string &ruleName, const std::set &rules) const; void addViolation(std::vector &dst, glw::GLenum code, const char *description) const; std::vector m_errorCodes; //!< Allowed GL errors, GL_NO_ERROR is not allowed std::vector 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(const glu::RenderContext &, const FormatDB &); virtual ~Checker(void) { } 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; const FormatDB &m_formats; private: ValidStatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus. }; class CheckerFactory { public: virtual Checker *createChecker(const glu::RenderContext &, const FormatDB &) = 0; }; typedef std::set AttachmentPoints; typedef std::set Formats; class FboVerifier { public: FboVerifier(const FormatDB &formats, CheckerFactory &factory, const glu::RenderContext &renderCtx); ValidStatusCodes validStatusCodes(const config::Framebuffer &cfg) const; private: const FormatDB &m_formats; CheckerFactory &m_factory; const glu::RenderContext &m_renderCtx; }; } // namespace FboUtil } // namespace gls } // namespace deqp #endif // _GLSFBOUTIL_HPP