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
59 {
60 return m_begin;
61 }
enddeqp::gls::Range62 const T *end(void) const
63 {
64 return m_end;
65 }
66 };
67
68 #define GLS_ARRAY_RANGE(ARR) \
69 { \
70 DE_ARRAY_BEGIN(ARR), DE_ARRAY_END(ARR) \
71 }
72
73 #define GLS_NULL_RANGE \
74 { \
75 DE_NULL, DE_NULL \
76 }
77
78 //! A pair type that, unlike stl::pair, is POD so it can be statically initialized.
79 template <typename T1, typename T2>
80 struct Pair
81 {
82 typedef T1 first_type;
83 typedef T2 second_type;
84 T1 first;
85 T2 second;
86 };
87
88 namespace FboUtil
89 {
90
91 //! Configurations for framebuffer objects and their attachments.
92
93 class FboVerifier;
94 class FboBuilder;
95
96 typedef uint32_t FormatKey;
97
98 #define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) (uint32_t(TYPE) << 16 | uint32_t(FORMAT))
99
100 typedef Range<FormatKey> FormatKeys;
101
102 struct ImageFormat
103 {
104 glw::GLenum format;
105
106 //! Type if format is unsized, GL_NONE if sized.
107 glw::GLenum unsizedType;
108
operator <deqp::gls::FboUtil::ImageFormat109 bool operator<(const ImageFormat &other) const
110 {
111 return (format < other.format || (format == other.format && unsizedType < other.unsizedType));
112 }
113
nonedeqp::gls::FboUtil::ImageFormat114 static ImageFormat none(void)
115 {
116 ImageFormat fmt = {GL_NONE, GL_NONE};
117 return fmt;
118 }
119 };
120
121 std::ostream &operator<<(std::ostream &stream, const ImageFormat &format);
122
formatKeyInfo(FormatKey key)123 static inline ImageFormat formatKeyInfo(FormatKey key)
124 {
125 ImageFormat fmt = {key & 0xffff, key >> 16};
126 return fmt;
127 }
128
129 enum FormatFlags
130 {
131 ANY_FORMAT = 0,
132 COLOR_RENDERABLE = 1 << 0,
133 DEPTH_RENDERABLE = 1 << 1,
134 STENCIL_RENDERABLE = 1 << 2,
135 RENDERBUFFER_VALID = 1 << 3,
136 TEXTURE_VALID = 1 << 4,
137 REQUIRED_RENDERABLE = 1 << 5, //< Without this, renderability is allowed, not required.
138 };
139
operator |(FormatFlags f1,FormatFlags f2)140 static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2)
141 {
142 return FormatFlags(uint32_t(f1) | uint32_t(f2));
143 }
144
145 FormatFlags formatFlag(glw::GLenum context);
146
147 typedef std::set<ImageFormat> Formats;
148
149 class FormatDB
150 {
151 public:
152 void addCoreFormat(ImageFormat format, FormatFlags flags);
153 void addExtensionFormat(ImageFormat format, FormatFlags flags, const std::set<std::string> &requiredExtensions);
154
155 Formats getFormats(FormatFlags requirements) const;
156 bool isKnownFormat(ImageFormat format) const;
157 FormatFlags getFormatInfo(ImageFormat format) const;
158 std::set<std::set<std::string>> getFormatFeatureExtensions(ImageFormat format, FormatFlags requirements) const;
159
160 private:
161 struct ExtensionInfo
162 {
163 FormatFlags flags;
164 std::set<std::string> requiredExtensions;
165
166 bool operator<(const ExtensionInfo &other) const;
167 };
168
169 typedef std::map<ImageFormat, FormatFlags> FormatMap;
170 typedef std::map<ImageFormat, std::set<ExtensionInfo>> FormatExtensionMap;
171
172 FormatMap m_formatFlags;
173 FormatExtensionMap m_formatExtensions;
174 };
175
176 typedef Pair<FormatFlags, FormatKeys> FormatEntry;
177 typedef Range<FormatEntry> FormatEntries;
178
179 // \todo [2013-12-20 lauri] It turns out that format properties in extensions
180 // are actually far too fine-grained for this bundling to be reasonable,
181 // especially given the syntactic cumbersomeness of static arrays. It's better
182 // to list each entry separately.
183
184 struct FormatExtEntry
185 {
186 const char *extensions;
187 uint32_t flags;
188 Range<FormatKey> formats;
189 };
190
191 typedef Range<FormatExtEntry> FormatExtEntries;
192
193 // Check support for GL_* and DEQP_* extensions
194 bool checkExtensionSupport(const glu::RenderContext &ctx, const std::string &extension);
195
196 // Accepts GL_* and DEQP_* extension strings and converts DEQP_* strings to a human readable string
197 std::string getExtensionDescription(const std::string &extensionName);
198
199 void addFormats(FormatDB &db, FormatEntries stdFmts);
200 void addExtFormats(FormatDB &db, FormatExtEntries extFmts, const glu::RenderContext *ctx);
201 glu::TransferFormat transferImageFormat(const ImageFormat &imgFormat);
202
203 namespace config
204 {
205
206 struct Config
207 {
~Configdeqp::gls::FboUtil::config::Config208 virtual ~Config(void)
209 {
210 }
211 };
212
213 struct Image : public Config
214 {
215 ImageFormat internalFormat;
216 glw::GLsizei width;
217 glw::GLsizei height;
218
219 protected:
Imagedeqp::gls::FboUtil::config::Image220 Image(void) : internalFormat(ImageFormat::none()), width(0), height(0)
221 {
222 }
223 };
224
225 struct Renderbuffer : public Image
226 {
Renderbufferdeqp::gls::FboUtil::config::Renderbuffer227 Renderbuffer(void) : numSamples(0)
228 {
229 }
230
231 glw::GLsizei numSamples;
232 };
233
234 struct Texture : public Image
235 {
Texturedeqp::gls::FboUtil::config::Texture236 Texture(void) : numLevels(1)
237 {
238 }
239
240 glw::GLint numLevels;
241 };
242
243 struct TextureFlat : public Texture
244 {
245 };
246
247 struct Texture2D : public TextureFlat
248 {
249 };
250
251 struct TextureCubeMap : public TextureFlat
252 {
253 };
254
255 struct TextureLayered : public Texture
256 {
TextureLayereddeqp::gls::FboUtil::config::TextureLayered257 TextureLayered(void) : numLayers(1)
258 {
259 }
260 glw::GLsizei numLayers;
261 };
262
263 struct Texture3D : public TextureLayered
264 {
265 };
266
267 struct Texture2DArray : public TextureLayered
268 {
269 };
270
271 struct Attachment : public Config
272 {
Attachmentdeqp::gls::FboUtil::config::Attachment273 Attachment(void) : target(GL_FRAMEBUFFER), imageName(0)
274 {
275 }
276
277 glw::GLenum target;
278 glw::GLuint imageName;
279
280 //! Returns `true` iff this attachment is "framebuffer attachment
281 //! complete" when bound to attachment point `attPoint`, and the current
282 //! image with name `imageName` is `image`, using `vfr` to check format
283 //! renderability.
284 bool isComplete(glw::GLenum attPoint, const Image *image, const FboVerifier &vfr) const;
285 };
286
287 struct RenderbufferAttachment : public Attachment
288 {
RenderbufferAttachmentdeqp::gls::FboUtil::config::RenderbufferAttachment289 RenderbufferAttachment(void) : renderbufferTarget(GL_RENDERBUFFER)
290 {
291 }
292
293 glw::GLenum renderbufferTarget;
294 };
295
296 struct TextureAttachment : public Attachment
297 {
TextureAttachmentdeqp::gls::FboUtil::config::TextureAttachment298 TextureAttachment(void) : level(0)
299 {
300 }
301
302 glw::GLint level;
303 };
304
305 struct TextureFlatAttachment : public TextureAttachment
306 {
TextureFlatAttachmentdeqp::gls::FboUtil::config::TextureFlatAttachment307 TextureFlatAttachment(void) : texTarget(GL_NONE)
308 {
309 }
310
311 glw::GLenum texTarget;
312 };
313
314 struct TextureLayerAttachment : public TextureAttachment
315 {
TextureLayerAttachmentdeqp::gls::FboUtil::config::TextureLayerAttachment316 TextureLayerAttachment(void) : layer(0)
317 {
318 }
319
320 glw::GLsizei layer;
321 };
322
323 glw::GLenum attachmentType(const Attachment &att);
324 glw::GLsizei imageNumSamples(const Image &img);
325
326 //! Mapping from attachment points to attachment configurations.
327 typedef std::map<glw::GLenum, const Attachment *> AttachmentMap;
328
329 //! Mapping from object names to texture configurations.
330 typedef std::map<glw::GLuint, const Texture *> TextureMap;
331
332 //! Mapping from object names to renderbuffer configurations.
333 typedef std::map<glw::GLuint, const Renderbuffer *> RboMap;
334
335 //! A framebuffer configuration.
336 struct Framebuffer
337 {
338 AttachmentMap attachments;
339 TextureMap textures;
340 RboMap rbos;
341
342 void attach(glw::GLenum attPoint, const Attachment *att);
343 void setTexture(glw::GLuint texName, const Texture &texCfg);
344 void setRbo(glw::GLuint rbName, const Renderbuffer &rbCfg);
345 const Image *getImage(glw::GLenum type, glw::GLuint imgName) const;
346 };
347
348 } // namespace config
349
350 class FboBuilder : public config::Framebuffer
351 {
352 public:
353 void glAttach(glw::GLenum attPoint, const config::Attachment *att);
354 glw::GLuint glCreateTexture(const config::Texture &texCfg);
355 glw::GLuint glCreateRbo(const config::Renderbuffer &rbCfg);
356 FboBuilder(glw::GLuint fbo, glw::GLenum target, const glw::Functions &gl);
357 ~FboBuilder(void);
getError(void)358 glw::GLenum getError(void)
359 {
360 return m_error;
361 }
362
363 //! Allocate a new configuration of type `Config` (which must be a
364 //! subclass of `config::Config`), and return a referenc to it. The newly
365 //! allocated object will be freed when this builder object is destroyed.
366 template <typename Config>
makeConfig(void)367 Config &makeConfig(void)
368 {
369 Config *cfg = new Config();
370 m_configs.insert(cfg);
371 return *cfg;
372 }
373
374 private:
375 typedef std::set<config::Config *> Configs;
376
377 void checkError(void);
378
379 glw::GLenum m_error; //< The first GL error encountered.
380 glw::GLenum m_target;
381 const glw::Functions &m_gl;
382 Configs m_configs;
383 };
384
385 struct ValidStatusCodes
386 {
387 ValidStatusCodes(void);
388
389 bool isFBOStatusValid(glw::GLenum fboStatus) const;
390 bool isFBOStatusRequired(glw::GLenum fboStatus) const;
391 bool isErrorCodeValid(glw::GLenum errorCode) const;
392 bool isErrorCodeRequired(glw::GLenum errorCode) const;
393
394 void addErrorCode(glw::GLenum error, const char *description);
395 void addFBOErrorStatus(glw::GLenum status, const char *description);
396 void setAllowComplete(bool);
397
398 void logLegalResults(tcu::TestLog &log) const;
399 void logRules(tcu::TestLog &log) const;
400
401 private:
402 struct RuleViolation
403 {
404 glw::GLenum errorCode;
405 std::set<std::string> rules;
406 };
407
408 void logRule(tcu::TestLog &log, const std::string &ruleName, const std::set<std::string> &rules) const;
409 void addViolation(std::vector<RuleViolation> &dst, glw::GLenum code, const char *description) const;
410
411 std::vector<RuleViolation> m_errorCodes; //!< Allowed GL errors, GL_NO_ERROR is not allowed
412 std::vector<RuleViolation> m_errorStatuses; //!< Allowed FBO error statuses, GL_FRAMEBUFFER_COMPLETE is not allowed
413 bool m_allowComplete; //!< true if (GL_NO_ERROR && GL_FRAMEBUFFER_COMPLETE) is allowed
414 };
415
416 void logFramebufferConfig(const config::Framebuffer &cfg, tcu::TestLog &log);
417
418 class Checker
419 {
420 public:
421 Checker(const glu::RenderContext &, const FormatDB &);
~Checker(void)422 virtual ~Checker(void)
423 {
424 }
425
426 void addGLError(glw::GLenum error, const char *description);
427 void addPotentialGLError(glw::GLenum error, const char *description);
428 void addFBOStatus(glw::GLenum status, const char *description);
429 void addPotentialFBOStatus(glw::GLenum status, const char *description);
430
getStatusCodes(void)431 ValidStatusCodes getStatusCodes(void)
432 {
433 return m_statusCodes;
434 }
435
436 virtual void check(glw::GLenum attPoint, const config::Attachment &att, const config::Image *image) = 0;
437
438 protected:
439 const glu::RenderContext &m_renderCtx;
440 const FormatDB &m_formats;
441
442 private:
443 ValidStatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus.
444 };
445
446 class CheckerFactory
447 {
448 public:
449 virtual Checker *createChecker(const glu::RenderContext &, const FormatDB &) = 0;
450 };
451
452 typedef std::set<glw::GLenum> AttachmentPoints;
453 typedef std::set<ImageFormat> Formats;
454
455 class FboVerifier
456 {
457 public:
458 FboVerifier(const FormatDB &formats, CheckerFactory &factory, const glu::RenderContext &renderCtx);
459
460 ValidStatusCodes validStatusCodes(const config::Framebuffer &cfg) const;
461
462 private:
463 const FormatDB &m_formats;
464 CheckerFactory &m_factory;
465 const glu::RenderContext &m_renderCtx;
466 };
467
468 } // namespace FboUtil
469 } // namespace gls
470 } // namespace deqp
471
472 #endif // _GLSFBOUTIL_HPP
473