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