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 42namespace deqp 43{ 44namespace 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? 52template <typename T> 53struct 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. 70template <typename T1, typename T2> 71struct Pair 72{ 73 typedef T1 first_type; 74 typedef T2 second_type; 75 T1 first; 76 T2 second; 77}; 78 79template<typename C> 80C 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? 89template<typename C> 90inline 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 96template <typename M> inline 97const 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 106template<typename M> inline 107const 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 116template<typename M> 117const 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 126template<typename C> 127inline 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 134template<typename M> static inline 135bool 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 142std::vector<std::string> splitString(const std::string& s); 143 144namespace FboUtil 145{ 146 147//! Configurations for framebuffer objects and their attachments. 148 149class FboVerifier; 150class FboBuilder; 151 152typedef deUint32 FormatKey; 153 154#define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \ 155 (deUint32(TYPE) << 16 | deUint32(FORMAT)) 156 157typedef Range<FormatKey> FormatKeys; 158 159struct 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 179static inline ImageFormat formatKeyInfo(FormatKey key) 180{ 181 ImageFormat fmt = { key & 0xffff, key >> 16 }; 182 return fmt; 183} 184 185enum 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 196static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2) 197{ 198 return FormatFlags(deUint32(f1) | deUint32(f2)); 199} 200 201FormatFlags formatFlag(glw::GLenum context); 202 203typedef std::set<ImageFormat> Formats; 204 205class FormatDB 206{ 207public: 208 void addFormat (ImageFormat format, FormatFlags flags); 209 Formats getFormats (FormatFlags requirements) const; 210 FormatFlags getFormatInfo (ImageFormat format, 211 FormatFlags fallback) const; 212 213private: 214 typedef std::map<ImageFormat, FormatFlags> FormatMap; 215 216 FormatMap m_map; 217}; 218 219typedef Pair<FormatFlags, FormatKeys> FormatEntry; 220typedef 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 227struct FormatExtEntry 228{ 229 const char* extensions; 230 deUint32 flags; 231 Range<FormatKey> formats; 232}; 233 234typedef Range<FormatExtEntry> FormatExtEntries; 235 236void addFormats (FormatDB& db, FormatEntries stdFmts); 237void addExtFormats (FormatDB& db, FormatExtEntries extFmts, 238 const glu::RenderContext* ctx); 239glu::TransferFormat transferImageFormat (const ImageFormat& imgFormat); 240 241namespace config 242{ 243 244struct Config 245{ 246 virtual ~Config (void) {}; 247}; 248 249struct Image : public Config 250{ 251 ImageFormat internalFormat; 252 glw::GLsizei width; 253 glw::GLsizei height; 254 255protected: 256 Image (void) 257 : internalFormat (ImageFormat::none()) 258 , width (0) 259 , height (0) {} 260}; 261 262struct Renderbuffer : public Image 263{ 264 Renderbuffer (void) : numSamples(0) {} 265 266 glw::GLsizei numSamples; 267}; 268 269struct Texture : public Image 270{ 271 Texture (void) : numLevels(1) {} 272 273 glw::GLint numLevels; 274}; 275 276struct TextureFlat : public Texture 277{ 278}; 279 280struct Texture2D : public TextureFlat 281{ 282}; 283 284struct TextureCubeMap : public TextureFlat 285{ 286}; 287 288struct TextureLayered : public Texture 289{ 290 TextureLayered (void) : numLayers(1) {} 291 glw::GLsizei numLayers; 292}; 293 294struct Texture3D : public TextureLayered 295{ 296}; 297 298struct Texture2DArray : public TextureLayered 299{ 300}; 301 302struct 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 317struct RenderbufferAttachment : public Attachment 318{ 319 RenderbufferAttachment (void) 320 : renderbufferTarget(GL_RENDERBUFFER) {} 321 322 glw::GLenum renderbufferTarget; 323}; 324 325struct TextureAttachment : public Attachment 326{ 327 TextureAttachment (void) : level(0) {} 328 329 glw::GLint level; 330}; 331 332struct TextureFlatAttachment : public TextureAttachment 333{ 334 TextureFlatAttachment (void) : texTarget(GL_NONE) {} 335 336 glw::GLenum texTarget; 337}; 338 339struct TextureLayerAttachment : public TextureAttachment 340{ 341 TextureLayerAttachment (void) : layer(0) {} 342 343 glw::GLsizei layer; 344}; 345 346glw::GLenum attachmentType (const Attachment& att); 347glw::GLsizei imageNumSamples (const Image& img); 348 349//! Mapping from attachment points to attachment configurations. 350typedef std::map<glw::GLenum, const Attachment*> AttachmentMap; 351 352//! Mapping from object names to texture configurations. 353typedef std::map<glw::GLuint, const Texture*> TextureMap; 354 355//! Mapping from object names to renderbuffer configurations. 356typedef std::map<glw::GLuint, const Renderbuffer*> RboMap; 357 358//! A framebuffer configuration. 359struct 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 373void logFramebufferConfig(const config::Framebuffer& cfg, tcu::TestLog& log); 374 375class FboBuilder : public config::Framebuffer 376{ 377public: 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 398private: 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 409typedef std::set<glw::GLenum> StatusCodes; 410 411class Checker 412{ 413public: 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; 421private: 422 423 StatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus. 424}; 425 426class CheckerFactory 427{ 428public: 429 virtual Checker* createChecker (void) = 0; 430}; 431 432typedef std::set<glw::GLenum> AttachmentPoints; 433typedef std::set<ImageFormat> Formats; 434 435class FboVerifier 436{ 437public: 438 FboVerifier (const FormatDB& formats, 439 CheckerFactory& factory); 440 441 StatusCodes validStatusCodes (const config::Framebuffer& cfg) const; 442 443private: 444 const FormatDB& m_formats; 445 CheckerFactory& m_factory; 446}; 447 448} // FboUtil 449} // gls 450} // deqp 451 452#endif // _GLSFBOUTIL_HPP 453