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