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 // Utilities for standard containers. \todo [2013-12-10 lauri] Move to decpp? 48 49 //! A pair of iterators to present a range. 50 //! \note This must be POD to allow static initialization. 51 //! \todo [2013-12-03 lauri] Move this to decpp? 52 template <typename T> 53 struct Range 54 { 55 typedef const T* const_iterator; 56 57 const T* m_begin; 58 const T* m_end; 59 60 const T* begin (void) const { return m_begin; } 61 const T* end (void) const { return m_end; } 62 }; 63 64 #define GLS_ARRAY_RANGE(ARR) { DE_ARRAY_BEGIN(ARR), DE_ARRAY_END(ARR) } 65 66 #define GLS_NULL_RANGE { DE_NULL, DE_NULL } 67 68 69 //! A pair type that, unlike stl::pair, is POD so it can be statically initialized. 70 template <typename T1, typename T2> 71 struct Pair 72 { 73 typedef T1 first_type; 74 typedef T2 second_type; 75 T1 first; 76 T2 second; 77 }; 78 79 template<typename C> 80 C intersection(const C& s1, const C& s2) 81 { 82 C ret; 83 std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), 84 std::insert_iterator<C>(ret, ret.begin())); 85 return ret; 86 } 87 88 // \todo [2013-12-03 lauri] move to decpp? 89 template<typename C> 90 inline bool isMember (const typename C::key_type& key, const C& container) 91 { 92 typename C::const_iterator it = container.find(key); 93 return (it != container.end()); 94 } 95 96 template <typename M> inline 97 const typename M::mapped_type* lookupMaybe (const M& map, 98 const typename M::key_type& key) 99 { 100 typename M::const_iterator it = map.find(key); 101 if (it == map.end()) 102 return DE_NULL; 103 return &it->second; 104 } 105 106 template<typename M> inline 107 const typename M::mapped_type& lookupDefault (const M& map, 108 const typename M::key_type& key, 109 const typename M::mapped_type& fallback) 110 { 111 const typename M::mapped_type* ptr = lookupMaybe(map, key); 112 return ptr == DE_NULL ? fallback : *ptr; 113 } 114 115 116 template<typename M> 117 const typename M::mapped_type& lookup (const M& map, 118 const typename M::key_type& key) 119 { 120 const typename M::mapped_type* ptr = lookupMaybe(map, key); 121 if (ptr == DE_NULL) 122 throw std::out_of_range("key not found in map"); 123 return *ptr; 124 } 125 126 template<typename C> 127 inline bool contains (const C& container, const typename C::value_type& item) 128 { 129 const typename C::const_iterator it = container.find(item); 130 return (it != container.end()); 131 } 132 133 134 template<typename M> static inline 135 bool insert(const typename M::key_type& key, const typename M::mapped_type& value, M& map) 136 { 137 typename M::value_type entry(key, value); 138 std::pair<typename M::iterator,bool> ret = map.insert(entry); 139 return ret.second; 140 } 141 142 std::vector<std::string> splitString(const std::string& s); 143 144 namespace FboUtil 145 { 146 147 //! Configurations for framebuffer objects and their attachments. 148 149 class FboVerifier; 150 class FboBuilder; 151 152 typedef deUint32 FormatKey; 153 154 #define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \ 155 (deUint32(TYPE) << 16 | deUint32(FORMAT)) 156 157 typedef Range<FormatKey> FormatKeys; 158 159 struct ImageFormat 160 { 161 glw::GLenum format; 162 163 //! Type if format is unsized, GL_NONE if sized. 164 glw::GLenum unsizedType; 165 166 bool operator< (const ImageFormat& other) const 167 { 168 return (format < other.format || 169 (format == other.format && unsizedType < other.unsizedType)); 170 } 171 172 static ImageFormat none (void) 173 { 174 ImageFormat fmt = { GL_NONE, GL_NONE }; 175 return fmt; 176 } 177 }; 178 179 static inline ImageFormat formatKeyInfo(FormatKey key) 180 { 181 ImageFormat fmt = { key & 0xffff, key >> 16 }; 182 return fmt; 183 } 184 185 enum FormatFlags 186 { 187 ANY_FORMAT = 0, 188 COLOR_RENDERABLE = 1 << 0, 189 DEPTH_RENDERABLE = 1 << 1, 190 STENCIL_RENDERABLE = 1 << 2, 191 RENDERBUFFER_VALID = 1 << 3, 192 TEXTURE_VALID = 1 << 4, 193 REQUIRED_RENDERABLE = 1 << 5, //< Without this, renderability is allowed, not required. 194 }; 195 196 static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2) 197 { 198 return FormatFlags(deUint32(f1) | deUint32(f2)); 199 } 200 201 FormatFlags formatFlag(glw::GLenum context); 202 203 typedef std::set<ImageFormat> Formats; 204 205 class FormatDB 206 { 207 public: 208 void addFormat (ImageFormat format, FormatFlags flags); 209 Formats getFormats (FormatFlags requirements) const; 210 FormatFlags getFormatInfo (ImageFormat format, 211 FormatFlags fallback) const; 212 213 private: 214 typedef std::map<ImageFormat, FormatFlags> FormatMap; 215 216 FormatMap m_map; 217 }; 218 219 typedef Pair<FormatFlags, FormatKeys> FormatEntry; 220 typedef Range<FormatEntry> FormatEntries; 221 222 // \todo [2013-12-20 lauri] It turns out that format properties in extensions 223 // are actually far too fine-grained for this bundling to be reasonable, 224 // especially given the syntactic cumbersomeness of static arrays. It's better 225 // to list each entry separately. 226 227 struct FormatExtEntry 228 { 229 const char* extensions; 230 deUint32 flags; 231 Range<FormatKey> formats; 232 }; 233 234 typedef Range<FormatExtEntry> FormatExtEntries; 235 236 void addFormats (FormatDB& db, FormatEntries stdFmts); 237 void addExtFormats (FormatDB& db, FormatExtEntries extFmts, 238 const glu::RenderContext* ctx); 239 glu::TransferFormat transferImageFormat (const ImageFormat& imgFormat); 240 241 namespace config 242 { 243 244 struct Config 245 { 246 virtual ~Config (void) {}; 247 }; 248 249 struct Image : public Config 250 { 251 ImageFormat internalFormat; 252 glw::GLsizei width; 253 glw::GLsizei height; 254 255 protected: 256 Image (void) 257 : internalFormat (ImageFormat::none()) 258 , width (0) 259 , height (0) {} 260 }; 261 262 struct Renderbuffer : public Image 263 { 264 Renderbuffer (void) : numSamples(0) {} 265 266 glw::GLsizei numSamples; 267 }; 268 269 struct Texture : public Image 270 { 271 Texture (void) : numLevels(1) {} 272 273 glw::GLint numLevels; 274 }; 275 276 struct TextureFlat : public Texture 277 { 278 }; 279 280 struct Texture2D : public TextureFlat 281 { 282 }; 283 284 struct TextureCubeMap : public TextureFlat 285 { 286 }; 287 288 struct TextureLayered : public Texture 289 { 290 TextureLayered (void) : numLayers(1) {} 291 glw::GLsizei numLayers; 292 }; 293 294 struct Texture3D : public TextureLayered 295 { 296 }; 297 298 struct Texture2DArray : public TextureLayered 299 { 300 }; 301 302 struct Attachment : public Config 303 { 304 Attachment (void) : target(GL_FRAMEBUFFER), imageName(0) {} 305 306 glw::GLenum target; 307 glw::GLuint imageName; 308 309 //! Returns `true` iff this attachment is "framebuffer attachment 310 //! complete" when bound to attachment point `attPoint`, and the current 311 //! image with name `imageName` is `image`, using `vfr` to check format 312 //! renderability. 313 bool isComplete (glw::GLenum attPoint, const Image* image, 314 const FboVerifier& vfr) const; 315 }; 316 317 struct RenderbufferAttachment : public Attachment 318 { 319 RenderbufferAttachment (void) 320 : renderbufferTarget(GL_RENDERBUFFER) {} 321 322 glw::GLenum renderbufferTarget; 323 }; 324 325 struct TextureAttachment : public Attachment 326 { 327 TextureAttachment (void) : level(0) {} 328 329 glw::GLint level; 330 }; 331 332 struct TextureFlatAttachment : public TextureAttachment 333 { 334 TextureFlatAttachment (void) : texTarget(GL_NONE) {} 335 336 glw::GLenum texTarget; 337 }; 338 339 struct TextureLayerAttachment : public TextureAttachment 340 { 341 TextureLayerAttachment (void) : layer(0) {} 342 343 glw::GLsizei layer; 344 }; 345 346 glw::GLenum attachmentType (const Attachment& att); 347 glw::GLsizei imageNumSamples (const Image& img); 348 349 //! Mapping from attachment points to attachment configurations. 350 typedef std::map<glw::GLenum, const Attachment*> AttachmentMap; 351 352 //! Mapping from object names to texture configurations. 353 typedef std::map<glw::GLuint, const Texture*> TextureMap; 354 355 //! Mapping from object names to renderbuffer configurations. 356 typedef std::map<glw::GLuint, const Renderbuffer*> RboMap; 357 358 //! A framebuffer configuration. 359 struct Framebuffer 360 { 361 AttachmentMap attachments; 362 TextureMap textures; 363 RboMap rbos; 364 365 void attach (glw::GLenum attPoint, const Attachment* att); 366 void setTexture (glw::GLuint texName, const Texture& texCfg); 367 void setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg); 368 const Image* getImage (glw::GLenum type, glw::GLuint imgName) const; 369 }; 370 371 } // config 372 373 void logFramebufferConfig(const config::Framebuffer& cfg, tcu::TestLog& log); 374 375 class FboBuilder : public config::Framebuffer 376 { 377 public: 378 void glAttach (glw::GLenum attPoint, 379 const config::Attachment* att); 380 glw::GLuint glCreateTexture (const config::Texture& texCfg); 381 glw::GLuint glCreateRbo (const config::Renderbuffer& rbCfg); 382 FboBuilder (glw::GLuint fbo, glw::GLenum target, 383 const glw::Functions& gl); 384 ~FboBuilder (void); 385 glw::GLenum getError (void) { return m_error; } 386 387 //! Allocate a new configuration of type `Config` (which must be a 388 //! subclass of `config::Config`), and return a referenc to it. The newly 389 //! allocated object will be freed when this builder object is destroyed. 390 template<typename Config> 391 Config& makeConfig (void) 392 { 393 Config* cfg = new Config(); 394 m_configs.insert(cfg); 395 return *cfg; 396 } 397 398 private: 399 typedef std::set<config::Config*> Configs; 400 401 void checkError (void); 402 403 glw::GLenum m_error; //< The first GL error encountered. 404 glw::GLenum m_target; 405 const glw::Functions& m_gl; 406 Configs m_configs; 407 }; 408 409 typedef std::set<glw::GLenum> StatusCodes; 410 411 class Checker 412 { 413 public: 414 Checker (void) { m_statusCodes.insert(GL_FRAMEBUFFER_COMPLETE); } 415 virtual ~Checker (void) {} 416 void require (bool condition, glw::GLenum error); 417 void canRequire (bool condition, glw::GLenum error); 418 StatusCodes getStatusCodes (void) { return m_statusCodes; } 419 virtual void check (glw::GLenum attPoint, const config::Attachment& att, 420 const config::Image* image) = 0; 421 private: 422 423 StatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus. 424 }; 425 426 class CheckerFactory 427 { 428 public: 429 virtual Checker* createChecker (void) = 0; 430 }; 431 432 typedef std::set<glw::GLenum> AttachmentPoints; 433 typedef std::set<ImageFormat> Formats; 434 435 class FboVerifier 436 { 437 public: 438 FboVerifier (const FormatDB& formats, 439 CheckerFactory& factory); 440 441 StatusCodes validStatusCodes (const config::Framebuffer& cfg) const; 442 443 private: 444 const FormatDB& m_formats; 445 CheckerFactory& m_factory; 446 }; 447 448 } // FboUtil 449 } // gls 450 } // deqp 451 452 #endif // _GLSFBOUTIL_HPP 453