1 #ifndef _GLSFBOUTIL_HPP 2 #define _GLSFBOUTIL_HPP 3 4 /*------------------------------------------------------------------------- 5 * drawElements Quality Program OpenGL (ES) Module 6 * ----------------------------------------------- 7 * 8 * Copyright 2014 The Android Open Source Project 9 * 10 * Licensed under the Apache License, Version 2.0 (the "License"); 11 * you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 * See the License for the specific language governing permissions and 20 * limitations under the License. 21 * 22 *//*! 23 * \file 24 * \brief Utilities for framebuffer objects. 25 *//*--------------------------------------------------------------------*/ 26 27 #include "gluRenderContext.hpp" 28 #include "gluContextInfo.hpp" 29 #include "glwDefs.hpp" 30 #include "glwEnums.hpp" 31 #include "glwFunctions.hpp" 32 #include "gluTextureUtil.hpp" 33 #include "tcuTestLog.hpp" 34 #include "tcuDefs.hpp" 35 36 #include <map> 37 #include <set> 38 #include <vector> 39 #include <algorithm> 40 #include <iterator> 41 42 namespace deqp 43 { 44 namespace gls 45 { 46 47 //! A pair of iterators to present a range. 48 //! \note This must be POD to allow static initialization. 49 //! \todo [2013-12-03 lauri] Move this to decpp? 50 template <typename T> 51 struct Range 52 { 53 typedef const T* const_iterator; 54 55 const T* m_begin; 56 const T* m_end; 57 58 const T* begin (void) const { return m_begin; } 59 const T* end (void) const { return m_end; } 60 }; 61 62 #define GLS_ARRAY_RANGE(ARR) { DE_ARRAY_BEGIN(ARR), DE_ARRAY_END(ARR) } 63 64 #define GLS_NULL_RANGE { DE_NULL, DE_NULL } 65 66 67 //! A pair type that, unlike stl::pair, is POD so it can be statically initialized. 68 template <typename T1, typename T2> 69 struct Pair 70 { 71 typedef T1 first_type; 72 typedef T2 second_type; 73 T1 first; 74 T2 second; 75 }; 76 77 namespace FboUtil 78 { 79 80 //! Configurations for framebuffer objects and their attachments. 81 82 class FboVerifier; 83 class FboBuilder; 84 85 typedef deUint32 FormatKey; 86 87 #define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \ 88 (deUint32(TYPE) << 16 | deUint32(FORMAT)) 89 90 typedef Range<FormatKey> FormatKeys; 91 92 struct ImageFormat 93 { 94 glw::GLenum format; 95 96 //! Type if format is unsized, GL_NONE if sized. 97 glw::GLenum unsizedType; 98 99 bool operator< (const ImageFormat& other) const 100 { 101 return (format < other.format || 102 (format == other.format && unsizedType < other.unsizedType)); 103 } 104 105 static ImageFormat none (void) 106 { 107 ImageFormat fmt = { GL_NONE, GL_NONE }; 108 return fmt; 109 } 110 }; 111 112 std::ostream& operator<< (std::ostream& stream, const ImageFormat& format); 113 114 static inline ImageFormat formatKeyInfo(FormatKey key) 115 { 116 ImageFormat fmt = { key & 0xffff, key >> 16 }; 117 return fmt; 118 } 119 120 enum FormatFlags 121 { 122 ANY_FORMAT = 0, 123 COLOR_RENDERABLE = 1 << 0, 124 DEPTH_RENDERABLE = 1 << 1, 125 STENCIL_RENDERABLE = 1 << 2, 126 RENDERBUFFER_VALID = 1 << 3, 127 TEXTURE_VALID = 1 << 4, 128 REQUIRED_RENDERABLE = 1 << 5, //< Without this, renderability is allowed, not required. 129 }; 130 131 static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2) 132 { 133 return FormatFlags(deUint32(f1) | deUint32(f2)); 134 } 135 136 FormatFlags formatFlag(glw::GLenum context); 137 138 typedef std::set<ImageFormat> Formats; 139 140 class FormatDB 141 { 142 public: 143 void addCoreFormat (ImageFormat format, FormatFlags flags); 144 void addExtensionFormat (ImageFormat format, FormatFlags flags, const std::set<std::string>& requiredExtensions); 145 146 Formats getFormats (FormatFlags requirements) const; 147 bool isKnownFormat (ImageFormat format) const; 148 FormatFlags getFormatInfo (ImageFormat format) const; 149 std::set<std::set<std::string> > getFormatFeatureExtensions (ImageFormat format, FormatFlags requirements) const; 150 151 private: 152 struct ExtensionInfo 153 { 154 FormatFlags flags; 155 std::set<std::string> requiredExtensions; 156 157 bool operator< (const ExtensionInfo& other) const; 158 }; 159 160 typedef std::map<ImageFormat, FormatFlags> FormatMap; 161 typedef std::map<ImageFormat, std::set<ExtensionInfo> > FormatExtensionMap; 162 163 FormatMap m_formatFlags; 164 FormatExtensionMap m_formatExtensions; 165 }; 166 167 typedef Pair<FormatFlags, FormatKeys> FormatEntry; 168 typedef Range<FormatEntry> FormatEntries; 169 170 // \todo [2013-12-20 lauri] It turns out that format properties in extensions 171 // are actually far too fine-grained for this bundling to be reasonable, 172 // especially given the syntactic cumbersomeness of static arrays. It's better 173 // to list each entry separately. 174 175 struct FormatExtEntry 176 { 177 const char* extensions; 178 deUint32 flags; 179 Range<FormatKey> formats; 180 }; 181 182 typedef Range<FormatExtEntry> FormatExtEntries; 183 184 // Check support for GL_* and DEQP_* extensions 185 bool checkExtensionSupport (const glu::RenderContext& ctx, const std::string& extension); 186 187 // Accepts GL_* and DEQP_* extension strings and converts DEQP_* strings to a human readable string 188 std::string getExtensionDescription (const std::string& extensionName); 189 190 void addFormats (FormatDB& db, FormatEntries stdFmts); 191 void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const glu::RenderContext* ctx); 192 glu::TransferFormat transferImageFormat (const ImageFormat& imgFormat); 193 194 namespace config 195 { 196 197 struct Config 198 { 199 virtual ~Config (void) {}; 200 }; 201 202 struct Image : public Config 203 { 204 ImageFormat internalFormat; 205 glw::GLsizei width; 206 glw::GLsizei height; 207 208 protected: 209 Image (void) 210 : internalFormat (ImageFormat::none()) 211 , width (0) 212 , height (0) {} 213 }; 214 215 struct Renderbuffer : public Image 216 { 217 Renderbuffer (void) : numSamples(0) {} 218 219 glw::GLsizei numSamples; 220 }; 221 222 struct Texture : public Image 223 { 224 Texture (void) : numLevels(1) {} 225 226 glw::GLint numLevels; 227 }; 228 229 struct TextureFlat : public Texture 230 { 231 }; 232 233 struct Texture2D : public TextureFlat 234 { 235 }; 236 237 struct TextureCubeMap : public TextureFlat 238 { 239 }; 240 241 struct TextureLayered : public Texture 242 { 243 TextureLayered (void) : numLayers(1) {} 244 glw::GLsizei numLayers; 245 }; 246 247 struct Texture3D : public TextureLayered 248 { 249 }; 250 251 struct Texture2DArray : public TextureLayered 252 { 253 }; 254 255 struct Attachment : public Config 256 { 257 Attachment (void) : target(GL_FRAMEBUFFER), imageName(0) {} 258 259 glw::GLenum target; 260 glw::GLuint imageName; 261 262 //! Returns `true` iff this attachment is "framebuffer attachment 263 //! complete" when bound to attachment point `attPoint`, and the current 264 //! image with name `imageName` is `image`, using `vfr` to check format 265 //! renderability. 266 bool isComplete (glw::GLenum attPoint, const Image* image, 267 const FboVerifier& vfr) const; 268 }; 269 270 struct RenderbufferAttachment : public Attachment 271 { 272 RenderbufferAttachment (void) 273 : renderbufferTarget(GL_RENDERBUFFER) {} 274 275 glw::GLenum renderbufferTarget; 276 }; 277 278 struct TextureAttachment : public Attachment 279 { 280 TextureAttachment (void) : level(0) {} 281 282 glw::GLint level; 283 }; 284 285 struct TextureFlatAttachment : public TextureAttachment 286 { 287 TextureFlatAttachment (void) : texTarget(GL_NONE) {} 288 289 glw::GLenum texTarget; 290 }; 291 292 struct TextureLayerAttachment : public TextureAttachment 293 { 294 TextureLayerAttachment (void) : layer(0) {} 295 296 glw::GLsizei layer; 297 }; 298 299 glw::GLenum attachmentType (const Attachment& att); 300 glw::GLsizei imageNumSamples (const Image& img); 301 302 //! Mapping from attachment points to attachment configurations. 303 typedef std::map<glw::GLenum, const Attachment*> AttachmentMap; 304 305 //! Mapping from object names to texture configurations. 306 typedef std::map<glw::GLuint, const Texture*> TextureMap; 307 308 //! Mapping from object names to renderbuffer configurations. 309 typedef std::map<glw::GLuint, const Renderbuffer*> RboMap; 310 311 //! A framebuffer configuration. 312 struct Framebuffer 313 { 314 AttachmentMap attachments; 315 TextureMap textures; 316 RboMap rbos; 317 318 void attach (glw::GLenum attPoint, const Attachment* att); 319 void setTexture (glw::GLuint texName, const Texture& texCfg); 320 void setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg); 321 const Image* getImage (glw::GLenum type, glw::GLuint imgName) const; 322 }; 323 324 } // config 325 326 class FboBuilder : public config::Framebuffer 327 { 328 public: 329 void glAttach (glw::GLenum attPoint, 330 const config::Attachment* att); 331 glw::GLuint glCreateTexture (const config::Texture& texCfg); 332 glw::GLuint glCreateRbo (const config::Renderbuffer& rbCfg); 333 FboBuilder (glw::GLuint fbo, glw::GLenum target, 334 const glw::Functions& gl); 335 ~FboBuilder (void); 336 glw::GLenum getError (void) { return m_error; } 337 338 //! Allocate a new configuration of type `Config` (which must be a 339 //! subclass of `config::Config`), and return a referenc to it. The newly 340 //! allocated object will be freed when this builder object is destroyed. 341 template<typename Config> 342 Config& makeConfig (void) 343 { 344 Config* cfg = new Config(); 345 m_configs.insert(cfg); 346 return *cfg; 347 } 348 349 private: 350 typedef std::set<config::Config*> Configs; 351 352 void checkError (void); 353 354 glw::GLenum m_error; //< The first GL error encountered. 355 glw::GLenum m_target; 356 const glw::Functions& m_gl; 357 Configs m_configs; 358 }; 359 360 struct ValidStatusCodes 361 { 362 ValidStatusCodes (void); 363 364 bool isFBOStatusValid (glw::GLenum fboStatus) const; 365 bool isFBOStatusRequired (glw::GLenum fboStatus) const; 366 bool isErrorCodeValid (glw::GLenum errorCode) const; 367 bool isErrorCodeRequired (glw::GLenum errorCode) const; 368 369 void addErrorCode (glw::GLenum error, const char* description); 370 void addFBOErrorStatus (glw::GLenum status, const char* description); 371 void setAllowComplete (bool); 372 373 void logLegalResults (tcu::TestLog& log) const; 374 void logRules (tcu::TestLog& log) const; 375 376 private: 377 struct RuleViolation 378 { 379 glw::GLenum errorCode; 380 std::set<std::string> rules; 381 }; 382 383 void logRule (tcu::TestLog& log, const std::string& ruleName, const std::set<std::string>& rules) const; 384 void addViolation (std::vector<RuleViolation>& dst, glw::GLenum code, const char* description) const; 385 386 std::vector<RuleViolation> m_errorCodes; //!< Allowed GL errors, GL_NO_ERROR is not allowed 387 std::vector<RuleViolation> m_errorStatuses; //!< Allowed FBO error statuses, GL_FRAMEBUFFER_COMPLETE is not allowed 388 bool m_allowComplete; //!< true if (GL_NO_ERROR && GL_FRAMEBUFFER_COMPLETE) is allowed 389 }; 390 391 void logFramebufferConfig (const config::Framebuffer& cfg, tcu::TestLog& log); 392 393 class Checker 394 { 395 public: 396 Checker (const glu::RenderContext&); 397 virtual ~Checker (void) {} 398 399 void addGLError (glw::GLenum error, const char* description); 400 void addPotentialGLError (glw::GLenum error, const char* description); 401 void addFBOStatus (glw::GLenum status, const char* description); 402 void addPotentialFBOStatus (glw::GLenum status, const char* description); 403 404 ValidStatusCodes getStatusCodes (void) { return m_statusCodes; } 405 406 virtual void check (glw::GLenum attPoint, 407 const config::Attachment& att, 408 const config::Image* image) = 0; 409 410 protected: 411 const glu::RenderContext& m_renderCtx; 412 413 private: 414 ValidStatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus. 415 }; 416 417 class CheckerFactory 418 { 419 public: 420 virtual Checker* createChecker (const glu::RenderContext&) = 0; 421 }; 422 423 typedef std::set<glw::GLenum> AttachmentPoints; 424 typedef std::set<ImageFormat> Formats; 425 426 class FboVerifier 427 { 428 public: 429 FboVerifier (const FormatDB& formats, 430 CheckerFactory& factory, 431 const glu::RenderContext& renderCtx); 432 433 ValidStatusCodes validStatusCodes (const config::Framebuffer& cfg) const; 434 435 private: 436 const FormatDB& m_formats; 437 CheckerFactory& m_factory; 438 const glu::RenderContext& m_renderCtx; 439 }; 440 441 } // FboUtil 442 } // gls 443 } // deqp 444 445 #endif // _GLSFBOUTIL_HPP 446