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// 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?
52template <typename T>
53struct Range
54{
55	typedef const T*	const_iterator;
56
57	const T*	m_begin;
58	const T*	m_end;
59
60	const T*	begin		(void) const { return m_begin; }
61	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.
70template <typename T1, typename T2>
71struct Pair
72{
73	typedef	T1	first_type;
74	typedef T2	second_type;
75	T1			first;
76	T2			second;
77};
78
79template<typename C>
80C 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?
89template<typename C>
90inline 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
96template <typename M> inline
97const 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
106template<typename M> inline
107const 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
116template<typename M>
117const 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
126template<typename C>
127inline 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
134template<typename M> static inline
135bool 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
142std::vector<std::string> splitString(const std::string& s);
143
144namespace FboUtil
145{
146
147//! Configurations for framebuffer objects and their attachments.
148
149class FboVerifier;
150class FboBuilder;
151
152typedef deUint32		FormatKey;
153
154#define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \
155	(deUint32(TYPE) << 16 | deUint32(FORMAT))
156
157typedef Range<FormatKey>	FormatKeys;
158
159struct ImageFormat
160{
161	glw::GLenum				format;
162
163	//! Type if format is unsized, GL_NONE if sized.
164	glw::GLenum				unsizedType;
165
166	bool 					operator<		(const ImageFormat& other) const
167	{
168		return (format < other.format ||
169				(format == other.format && unsizedType < other.unsizedType));
170	}
171
172	static ImageFormat		none			(void)
173	{
174		ImageFormat fmt = { GL_NONE, GL_NONE };
175		return fmt;
176	}
177};
178
179static inline ImageFormat formatKeyInfo(FormatKey key)
180{
181	ImageFormat fmt = { key & 0xffff, key >> 16 };
182	return fmt;
183}
184
185enum 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
196static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2)
197{
198	return FormatFlags(deUint32(f1) | deUint32(f2));
199}
200
201FormatFlags formatFlag(glw::GLenum context);
202
203typedef std::set<ImageFormat> Formats;
204
205class FormatDB
206{
207public:
208	void							addFormat		(ImageFormat format, FormatFlags flags);
209	Formats							getFormats		(FormatFlags requirements) const;
210	FormatFlags						getFormatInfo	(ImageFormat format,
211													 FormatFlags fallback) const;
212
213private:
214	typedef std::map<ImageFormat, FormatFlags>		FormatMap;
215
216	FormatMap						m_map;
217};
218
219typedef Pair<FormatFlags, FormatKeys>				FormatEntry;
220typedef 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
227struct FormatExtEntry
228{
229	const char*									extensions;
230	deUint32									flags;
231	Range<FormatKey>							formats;
232};
233
234typedef Range<FormatExtEntry>						FormatExtEntries;
235
236void				addFormats			(FormatDB& db, FormatEntries stdFmts);
237void 				addExtFormats		(FormatDB& db, FormatExtEntries extFmts,
238										 const glu::RenderContext* ctx);
239glu::TransferFormat	transferImageFormat	(const ImageFormat& imgFormat);
240
241namespace config
242{
243
244struct Config
245{
246	virtual 					~Config			(void) {};
247};
248
249struct Image : public Config
250{
251	ImageFormat					internalFormat;
252	glw::GLsizei				width;
253	glw::GLsizei				height;
254
255protected:
256								Image			(void)
257									: internalFormat	(ImageFormat::none())
258									, width				(0)
259									, height			(0) {}
260};
261
262struct Renderbuffer : public Image
263{
264						Renderbuffer	(void) : numSamples(0) {}
265
266	glw::GLsizei		numSamples;
267};
268
269struct Texture : public Image
270{
271							Texture			(void) : numLevels(1) {}
272
273	glw::GLint 				numLevels;
274};
275
276struct TextureFlat : public Texture
277{
278};
279
280struct Texture2D : public TextureFlat
281{
282};
283
284struct TextureCubeMap : public TextureFlat
285{
286};
287
288struct TextureLayered : public Texture
289{
290							TextureLayered	(void) : numLayers(1) {}
291	glw::GLsizei			numLayers;
292};
293
294struct Texture3D : public TextureLayered
295{
296};
297
298struct Texture2DArray : public TextureLayered
299{
300};
301
302struct Attachment : public Config
303{
304							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
317struct RenderbufferAttachment : public Attachment
318{
319				RenderbufferAttachment	(void)
320				: renderbufferTarget(GL_RENDERBUFFER) {}
321
322	glw::GLenum renderbufferTarget;
323};
324
325struct TextureAttachment : public Attachment
326{
327							TextureAttachment	(void) : level(0) {}
328
329	glw::GLint				level;
330};
331
332struct TextureFlatAttachment : public TextureAttachment
333{
334							TextureFlatAttachment (void) : texTarget(GL_NONE) {}
335
336	glw::GLenum				texTarget;
337};
338
339struct TextureLayerAttachment : public TextureAttachment
340{
341							TextureLayerAttachment (void) : layer(0) {}
342
343	glw::GLsizei			layer;
344};
345
346glw::GLenum		attachmentType	(const Attachment& att);
347glw::GLsizei	imageNumSamples	(const Image& img);
348
349//! Mapping from attachment points to attachment configurations.
350typedef std::map<glw::GLenum, const Attachment*> AttachmentMap;
351
352//! Mapping from object names to texture configurations.
353typedef std::map<glw::GLuint, const Texture*> TextureMap;
354
355//! Mapping from object names to renderbuffer configurations.
356typedef std::map<glw::GLuint, const Renderbuffer*> RboMap;
357
358//! A framebuffer configuration.
359struct 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
373void logFramebufferConfig(const config::Framebuffer& cfg, tcu::TestLog& log);
374
375class FboBuilder : public config::Framebuffer
376{
377public:
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);
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>
391	Config&						makeConfig		(void)
392	{
393		Config* cfg = new Config();
394		m_configs.insert(cfg);
395		return *cfg;
396	}
397
398private:
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
409typedef std::set<glw::GLenum> StatusCodes;
410
411class Checker
412{
413public:
414					Checker			(void) { m_statusCodes.insert(GL_FRAMEBUFFER_COMPLETE); }
415	virtual			~Checker		(void) {}
416	void			require			(bool condition, glw::GLenum error);
417	void			canRequire		(bool condition, glw::GLenum error);
418	StatusCodes		getStatusCodes	(void) { return m_statusCodes; }
419	virtual void	check			(glw::GLenum attPoint, const config::Attachment& att,
420									 const config::Image* image) = 0;
421private:
422
423	StatusCodes		m_statusCodes;	//< Allowed return values for glCheckFramebufferStatus.
424};
425
426class CheckerFactory
427{
428public:
429	virtual Checker*	createChecker	(void) = 0;
430};
431
432typedef std::set<glw::GLenum> AttachmentPoints;
433typedef std::set<ImageFormat> Formats;
434
435class FboVerifier
436{
437public:
438								FboVerifier				(const FormatDB& formats,
439														 CheckerFactory& factory);
440
441	StatusCodes					validStatusCodes		(const config::Framebuffer& cfg) const;
442
443private:
444	const FormatDB&				m_formats;
445	CheckerFactory&				m_factory;
446};
447
448} // FboUtil
449} // gls
450} // deqp
451
452#endif // _GLSFBOUTIL_HPP
453