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
begindeqp::gls::Range58 const T* begin (void) const { return m_begin; }
enddeqp::gls::Range59 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
operator <deqp::gls::FboUtil::ImageFormat99 bool operator< (const ImageFormat& other) const
100 {
101 return (format < other.format ||
102 (format == other.format && unsizedType < other.unsizedType));
103 }
104
nonedeqp::gls::FboUtil::ImageFormat105 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
formatKeyInfo(FormatKey key)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
operator |(FormatFlags f1,FormatFlags f2)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 {
~Configdeqp::gls::FboUtil::config::Config199 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:
Imagedeqp::gls::FboUtil::config::Image209 Image (void)
210 : internalFormat (ImageFormat::none())
211 , width (0)
212 , height (0) {}
213 };
214
215 struct Renderbuffer : public Image
216 {
Renderbufferdeqp::gls::FboUtil::config::Renderbuffer217 Renderbuffer (void) : numSamples(0) {}
218
219 glw::GLsizei numSamples;
220 };
221
222 struct Texture : public Image
223 {
Texturedeqp::gls::FboUtil::config::Texture224 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 {
TextureLayereddeqp::gls::FboUtil::config::TextureLayered243 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 {
Attachmentdeqp::gls::FboUtil::config::Attachment257 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 {
RenderbufferAttachmentdeqp::gls::FboUtil::config::RenderbufferAttachment272 RenderbufferAttachment (void)
273 : renderbufferTarget(GL_RENDERBUFFER) {}
274
275 glw::GLenum renderbufferTarget;
276 };
277
278 struct TextureAttachment : public Attachment
279 {
TextureAttachmentdeqp::gls::FboUtil::config::TextureAttachment280 TextureAttachment (void) : level(0) {}
281
282 glw::GLint level;
283 };
284
285 struct TextureFlatAttachment : public TextureAttachment
286 {
TextureFlatAttachmentdeqp::gls::FboUtil::config::TextureFlatAttachment287 TextureFlatAttachment (void) : texTarget(GL_NONE) {}
288
289 glw::GLenum texTarget;
290 };
291
292 struct TextureLayerAttachment : public TextureAttachment
293 {
TextureLayerAttachmentdeqp::gls::FboUtil::config::TextureLayerAttachment294 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);
getError(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>
makeConfig(void)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&);
~Checker(void)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
getStatusCodes(void)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