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
begindeqp::gls::Range60 const T* begin (void) const { return m_begin; }
enddeqp::gls::Range61 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>
intersection(const C & s1,const C & s2)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>
isMember(const typename C::key_type & key,const C & container)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
lookupMaybe(const M & map,const typename M::key_type & key)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
lookupDefault(const M & map,const typename M::key_type & key,const typename M::mapped_type & fallback)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>
lookup(const M & map,const typename M::key_type & key)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>
contains(const C & container,const typename C::value_type & item)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
insert(const typename M::key_type & key,const typename M::mapped_type & value,M & map)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
operator <deqp::gls::FboUtil::ImageFormat166 bool operator< (const ImageFormat& other) const
167 {
168 return (format < other.format ||
169 (format == other.format && unsizedType < other.unsizedType));
170 }
171
nonedeqp::gls::FboUtil::ImageFormat172 static ImageFormat none (void)
173 {
174 ImageFormat fmt = { GL_NONE, GL_NONE };
175 return fmt;
176 }
177 };
178
formatKeyInfo(FormatKey key)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
operator |(FormatFlags f1,FormatFlags f2)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 {
~Configdeqp::gls::FboUtil::config::Config246 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:
Imagedeqp::gls::FboUtil::config::Image256 Image (void)
257 : internalFormat (ImageFormat::none())
258 , width (0)
259 , height (0) {}
260 };
261
262 struct Renderbuffer : public Image
263 {
Renderbufferdeqp::gls::FboUtil::config::Renderbuffer264 Renderbuffer (void) : numSamples(0) {}
265
266 glw::GLsizei numSamples;
267 };
268
269 struct Texture : public Image
270 {
Texturedeqp::gls::FboUtil::config::Texture271 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 {
TextureLayereddeqp::gls::FboUtil::config::TextureLayered290 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 {
Attachmentdeqp::gls::FboUtil::config::Attachment304 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 {
RenderbufferAttachmentdeqp::gls::FboUtil::config::RenderbufferAttachment319 RenderbufferAttachment (void)
320 : renderbufferTarget(GL_RENDERBUFFER) {}
321
322 glw::GLenum renderbufferTarget;
323 };
324
325 struct TextureAttachment : public Attachment
326 {
TextureAttachmentdeqp::gls::FboUtil::config::TextureAttachment327 TextureAttachment (void) : level(0) {}
328
329 glw::GLint level;
330 };
331
332 struct TextureFlatAttachment : public TextureAttachment
333 {
TextureFlatAttachmentdeqp::gls::FboUtil::config::TextureFlatAttachment334 TextureFlatAttachment (void) : texTarget(GL_NONE) {}
335
336 glw::GLenum texTarget;
337 };
338
339 struct TextureLayerAttachment : public TextureAttachment
340 {
TextureLayerAttachmentdeqp::gls::FboUtil::config::TextureLayerAttachment341 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);
getError(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>
makeConfig(void)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:
Checker(void)414 Checker (void) { m_statusCodes.insert(GL_FRAMEBUFFER_COMPLETE); }
~Checker(void)415 virtual ~Checker (void) {}
416 void require (bool condition, glw::GLenum error);
417 void canRequire (bool condition, glw::GLenum error);
getStatusCodes(void)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