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//! 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?
50template <typename T>
51struct Range
52{
53	typedef const T*	const_iterator;
54
55	const T*	m_begin;
56	const T*	m_end;
57
58	const T*	begin		(void) const { return m_begin; }
59	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.
68template <typename T1, typename T2>
69struct Pair
70{
71	typedef	T1	first_type;
72	typedef T2	second_type;
73	T1			first;
74	T2			second;
75};
76
77namespace FboUtil
78{
79
80//! Configurations for framebuffer objects and their attachments.
81
82class FboVerifier;
83class FboBuilder;
84
85typedef deUint32		FormatKey;
86
87#define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \
88	(deUint32(TYPE) << 16 | deUint32(FORMAT))
89
90typedef Range<FormatKey>	FormatKeys;
91
92struct ImageFormat
93{
94	glw::GLenum				format;
95
96	//! Type if format is unsized, GL_NONE if sized.
97	glw::GLenum				unsizedType;
98
99	bool					operator<		(const ImageFormat& other) const
100	{
101		return (format < other.format ||
102				(format == other.format && unsizedType < other.unsizedType));
103	}
104
105	static ImageFormat		none			(void)
106	{
107		ImageFormat fmt = { GL_NONE, GL_NONE };
108		return fmt;
109	}
110};
111
112std::ostream& operator<< (std::ostream& stream, const ImageFormat& format);
113
114static inline ImageFormat formatKeyInfo(FormatKey key)
115{
116	ImageFormat fmt = { key & 0xffff, key >> 16 };
117	return fmt;
118}
119
120enum 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
131static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2)
132{
133	return FormatFlags(deUint32(f1) | deUint32(f2));
134}
135
136FormatFlags formatFlag(glw::GLenum context);
137
138typedef std::set<ImageFormat> Formats;
139
140class FormatDB
141{
142public:
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
151private:
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
167typedef Pair<FormatFlags, FormatKeys>				FormatEntry;
168typedef 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
175struct FormatExtEntry
176{
177	const char*									extensions;
178	deUint32									flags;
179	Range<FormatKey>							formats;
180};
181
182typedef Range<FormatExtEntry>						FormatExtEntries;
183
184// Check support for GL_* and DEQP_* extensions
185bool				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
188std::string			getExtensionDescription		(const std::string& extensionName);
189
190void				addFormats					(FormatDB& db, FormatEntries stdFmts);
191void				addExtFormats				(FormatDB& db, FormatExtEntries extFmts, const glu::RenderContext* ctx);
192glu::TransferFormat	transferImageFormat			(const ImageFormat& imgFormat);
193
194namespace config
195{
196
197struct Config
198{
199	virtual						~Config			(void) {};
200};
201
202struct Image : public Config
203{
204	ImageFormat					internalFormat;
205	glw::GLsizei				width;
206	glw::GLsizei				height;
207
208protected:
209								Image			(void)
210									: internalFormat	(ImageFormat::none())
211									, width				(0)
212									, height			(0) {}
213};
214
215struct Renderbuffer : public Image
216{
217						Renderbuffer	(void) : numSamples(0) {}
218
219	glw::GLsizei		numSamples;
220};
221
222struct Texture : public Image
223{
224							Texture			(void) : numLevels(1) {}
225
226	glw::GLint				numLevels;
227};
228
229struct TextureFlat : public Texture
230{
231};
232
233struct Texture2D : public TextureFlat
234{
235};
236
237struct TextureCubeMap : public TextureFlat
238{
239};
240
241struct TextureLayered : public Texture
242{
243							TextureLayered	(void) : numLayers(1) {}
244	glw::GLsizei			numLayers;
245};
246
247struct Texture3D : public TextureLayered
248{
249};
250
251struct Texture2DArray : public TextureLayered
252{
253};
254
255struct Attachment : public Config
256{
257							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
270struct RenderbufferAttachment : public Attachment
271{
272				RenderbufferAttachment	(void)
273				: renderbufferTarget(GL_RENDERBUFFER) {}
274
275	glw::GLenum renderbufferTarget;
276};
277
278struct TextureAttachment : public Attachment
279{
280							TextureAttachment	(void) : level(0) {}
281
282	glw::GLint				level;
283};
284
285struct TextureFlatAttachment : public TextureAttachment
286{
287							TextureFlatAttachment (void) : texTarget(GL_NONE) {}
288
289	glw::GLenum				texTarget;
290};
291
292struct TextureLayerAttachment : public TextureAttachment
293{
294							TextureLayerAttachment (void) : layer(0) {}
295
296	glw::GLsizei			layer;
297};
298
299glw::GLenum		attachmentType	(const Attachment& att);
300glw::GLsizei	imageNumSamples	(const Image& img);
301
302//! Mapping from attachment points to attachment configurations.
303typedef std::map<glw::GLenum, const Attachment*> AttachmentMap;
304
305//! Mapping from object names to texture configurations.
306typedef std::map<glw::GLuint, const Texture*> TextureMap;
307
308//! Mapping from object names to renderbuffer configurations.
309typedef std::map<glw::GLuint, const Renderbuffer*> RboMap;
310
311//! A framebuffer configuration.
312struct 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
326class FboBuilder : public config::Framebuffer
327{
328public:
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);
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>
342	Config&						makeConfig		(void)
343	{
344		Config* cfg = new Config();
345		m_configs.insert(cfg);
346		return *cfg;
347	}
348
349private:
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
360struct 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
376private:
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
391void logFramebufferConfig (const config::Framebuffer& cfg, tcu::TestLog& log);
392
393class Checker
394{
395public:
396								Checker					(const glu::RenderContext&);
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
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
410protected:
411	const glu::RenderContext&	m_renderCtx;
412
413private:
414	ValidStatusCodes			m_statusCodes;	//< Allowed return values for glCheckFramebufferStatus.
415};
416
417class CheckerFactory
418{
419public:
420	virtual Checker*	createChecker	(const glu::RenderContext&) = 0;
421};
422
423typedef std::set<glw::GLenum> AttachmentPoints;
424typedef std::set<ImageFormat> Formats;
425
426class FboVerifier
427{
428public:
429								FboVerifier				(const FormatDB&			formats,
430														 CheckerFactory&			factory,
431														 const glu::RenderContext&	renderCtx);
432
433	ValidStatusCodes			validStatusCodes		(const config::Framebuffer& cfg) const;
434
435private:
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