| #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 deUint32 FormatKey; |
| |
| #define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \ |
| (deUint32(TYPE) << 16 | deUint32(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(deUint32(f1) | deUint32(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; |
| deUint32 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; |
| }; |
| |
| } // 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&); |
| 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; |
| |
| private: |
| ValidStatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus. |
| }; |
| |
| class CheckerFactory |
| { |
| public: |
| virtual Checker* createChecker (const glu::RenderContext&) = 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; |
| }; |
| |
| } // FboUtil |
| } // gls |
| } // deqp |
| |
| #endif // _GLSFBOUTIL_HPP |