| #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 <map> |
| #include <set> |
| #include <vector> |
| #include <algorithm> |
| #include <iterator> |
| |
| 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 <typename T> |
| 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 <typename T1, typename T2> |
| 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<FormatKey> 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<ImageFormat> Formats; |
| |
| class FormatDB |
| { |
| public: |
| 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: |
| struct ExtensionInfo |
| { |
| FormatFlags flags; |
| std::set<std::string> requiredExtensions; |
| |
| 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; |
| typedef Range<FormatEntry> 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<FormatKey> formats; |
| }; |
| |
| typedef Range<FormatExtEntry> 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<glw::GLenum, const Attachment *> AttachmentMap; |
| |
| //! Mapping from object names to texture configurations. |
| typedef std::map<glw::GLuint, const Texture *> TextureMap; |
| |
| //! Mapping from object names to renderbuffer configurations. |
| typedef std::map<glw::GLuint, const Renderbuffer *> 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 <typename Config> |
| Config &makeConfig(void) |
| { |
| Config *cfg = new Config(); |
| m_configs.insert(cfg); |
| return *cfg; |
| } |
| |
| private: |
| typedef std::set<config::Config *> 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<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(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<glw::GLenum> AttachmentPoints; |
| typedef std::set<ImageFormat> 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 |