• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) Module
3  * -----------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Utilities for framebuffer objects.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsFboUtil.hpp"
25 
26 #include "glwEnums.hpp"
27 #include "deUniquePtr.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluStrUtil.hpp"
30 #include "deStringUtil.hpp"
31 #include <sstream>
32 
33 using namespace glw;
34 using tcu::TestLog;
35 using tcu::TextureFormat;
36 using tcu::NotSupportedError;
37 using glu::TransferFormat;
38 using glu::mapGLInternalFormat;
39 using glu::mapGLTransferFormat;
40 using glu::getPixelFormatName;
41 using glu::getTypeName;
42 using glu::getFramebufferTargetName;
43 using glu::getFramebufferAttachmentName;
44 using glu::getFramebufferAttachmentTypeName;
45 using glu::getTextureTargetName;
46 using glu::getTransferFormat;
47 using glu::ContextInfo;
48 using glu::ContextType;
49 using glu::RenderContext;
50 using de::UniquePtr;
51 using de::toString;
52 using std::set;
53 using std::vector;
54 using std::string;
55 using std::istringstream;
56 using std::istream_iterator;
57 
58 namespace deqp
59 {
60 namespace gls
61 {
62 
63 namespace FboUtil
64 {
65 
66 
addFormat(ImageFormat format,FormatFlags newFlags)67 void FormatDB::addFormat (ImageFormat format, FormatFlags newFlags)
68 {
69 	FormatFlags& flags = m_map[format];
70 	flags = FormatFlags(flags | newFlags);
71 }
72 
73 // Not too fast at the moment, might consider indexing?
getFormats(FormatFlags requirements) const74 Formats FormatDB::getFormats (FormatFlags requirements) const
75 {
76 	Formats ret;
77 	for (FormatMap::const_iterator it = m_map.begin(); it != m_map.end(); it++)
78 	{
79 		if ((it->second & requirements) == requirements)
80 			ret.insert(it->first);
81 	}
82 	return ret;
83 }
84 
getFormatInfo(ImageFormat format,FormatFlags fallback) const85 FormatFlags FormatDB::getFormatInfo (ImageFormat format, FormatFlags fallback) const
86 {
87 	return lookupDefault(m_map, format, fallback);
88 }
89 
addFormats(FormatDB & db,FormatEntries stdFmts)90 void addFormats (FormatDB& db, FormatEntries stdFmts)
91 {
92 	for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++)
93 	{
94 		for (const FormatKey* it2 = it->second.begin(); it2 != it->second.end(); it2++)
95 			db.addFormat(formatKeyInfo(*it2), it->first);
96 	}
97 }
98 
addExtFormats(FormatDB & db,FormatExtEntries extFmts,const RenderContext * ctx)99 void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const RenderContext* ctx)
100 {
101 	const UniquePtr<ContextInfo> ctxInfo(ctx != DE_NULL ? ContextInfo::create(*ctx) : DE_NULL);
102 	for (const FormatExtEntry* it = extFmts.begin(); it != extFmts.end(); it++)
103 	{
104 		bool supported = true;
105 		if (ctxInfo)
106 		{
107 			istringstream tokenStream(string(it->extensions));
108 			istream_iterator<string> tokens((tokenStream)), end;
109 
110 			while (tokens != end)
111 			{
112 				if (!ctxInfo->isExtensionSupported(tokens->c_str()))
113 				{
114 					supported = false;
115 					break;
116 				}
117 				++tokens;
118 			}
119 		}
120 		if (supported)
121 			for (const FormatKey* i2 = it->formats.begin(); i2 != it->formats.end(); i2++)
122 				db.addFormat(formatKeyInfo(*i2), FormatFlags(it->flags));
123 	}
124 }
125 
formatFlag(GLenum context)126 FormatFlags formatFlag (GLenum context)
127 {
128 	switch (context)
129 	{
130 		case GL_NONE:
131 			return FormatFlags(0);
132 		case GL_RENDERBUFFER:
133 			return RENDERBUFFER_VALID;
134 		case GL_TEXTURE:
135 			return TEXTURE_VALID;
136 		case GL_STENCIL_ATTACHMENT:
137 			return STENCIL_RENDERABLE;
138 		case GL_DEPTH_ATTACHMENT:
139 			return DEPTH_RENDERABLE;
140 		default:
141 			DE_ASSERT(context >= GL_COLOR_ATTACHMENT0 && context <= GL_COLOR_ATTACHMENT15);
142 			return COLOR_RENDERABLE;
143 	}
144 }
145 
146 namespace config {
147 
imageNumSamples(const Image & img)148 GLsizei	imageNumSamples	(const Image& img)
149 {
150 	if (const Renderbuffer* rbo = dynamic_cast<const Renderbuffer*>(&img))
151 		return rbo->numSamples;
152 	return 0;
153 }
154 
glTarget(const Image & img)155 static GLenum glTarget (const Image& img)
156 {
157 	if (dynamic_cast<const Renderbuffer*>(&img) != DE_NULL)
158 		return GL_RENDERBUFFER;
159 	if (dynamic_cast<const Texture2D*>(&img) != DE_NULL)
160 		return GL_TEXTURE_2D;
161 	if (dynamic_cast<const TextureCubeMap*>(&img) != DE_NULL)
162 		return GL_TEXTURE_CUBE_MAP;
163 	if (dynamic_cast<const Texture3D*>(&img) != DE_NULL)
164 		return GL_TEXTURE_3D;
165 	if (dynamic_cast<const Texture2DArray*>(&img) != DE_NULL)
166 		return GL_TEXTURE_2D_ARRAY;
167 
168 	DE_ASSERT(!"Impossible image type");
169 	return GL_NONE;
170 }
171 
glInitFlat(const TextureFlat & cfg,GLenum target,const glw::Functions & gl)172 static void glInitFlat (const TextureFlat& cfg, GLenum target, const glw::Functions& gl)
173 {
174 	const TransferFormat format = transferImageFormat(cfg.internalFormat);
175 	GLint w = cfg.width;
176 	GLint h = cfg.height;
177 	for (GLint level = 0; level < cfg.numLevels; level++)
178 	{
179 		gl.texImage2D(target, level, cfg.internalFormat.format, w, h, 0,
180 					  format.format, format.dataType, DE_NULL);
181 		w = de::max(1, w / 2);
182 		h = de::max(1, h / 2);
183 	}
184 }
185 
glInitLayered(const TextureLayered & cfg,GLint depth_divider,const glw::Functions & gl)186 static void glInitLayered (const TextureLayered& cfg,
187 						   GLint depth_divider, const glw::Functions& gl)
188 {
189 	const TransferFormat format = transferImageFormat(cfg.internalFormat);
190 	GLint w = cfg.width;
191 	GLint h = cfg.height;
192 	GLint depth = cfg.numLayers;
193 	for (GLint level = 0; level < cfg.numLevels; level++)
194 	{
195 		gl.texImage3D(glTarget(cfg), level, cfg.internalFormat.format, w, h, depth, 0,
196 					  format.format, format.dataType, DE_NULL);
197 		w = de::max(1, w / 2);
198 		h = de::max(1, h / 2);
199 		depth = de::max(1, depth / depth_divider);
200 	}
201 }
202 
glInit(const Texture & cfg,const glw::Functions & gl)203 static void glInit (const Texture& cfg, const glw::Functions& gl)
204 {
205 	if (const Texture2D* t2d = dynamic_cast<const Texture2D*>(&cfg))
206 		glInitFlat(*t2d, glTarget(*t2d), gl);
207 	else if (const TextureCubeMap* tcm = dynamic_cast<const TextureCubeMap*>(&cfg))
208 	{
209 		// \todo [2013-12-05 lauri]
210 		// move this to glu or someplace sensible (this array is already
211 		// present in duplicates)
212 		static const GLenum s_cubeMapFaces[] =
213 			{
214 				GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
215 				GL_TEXTURE_CUBE_MAP_POSITIVE_X,
216 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
217 				GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
218 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
219 				GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
220 			};
221 		const Range<GLenum> range = GLS_ARRAY_RANGE(s_cubeMapFaces);
222 		for (const GLenum* it = range.begin(); it != range.end(); it++)
223 			glInitFlat(*tcm, *it, gl);
224 	}
225 	else if (const Texture3D* t3d = dynamic_cast<const Texture3D*>(&cfg))
226 		glInitLayered(*t3d, 2, gl);
227 	else if (const Texture2DArray* t2a = dynamic_cast<const Texture2DArray*>(&cfg))
228 		glInitLayered(*t2a, 1, gl);
229 }
230 
glCreate(const Image & cfg,const glw::Functions & gl)231 static GLuint glCreate (const Image& cfg, const glw::Functions& gl)
232 {
233 	GLuint ret = 0;
234 	if (const Renderbuffer* const rbo = dynamic_cast<const Renderbuffer*>(&cfg))
235 	{
236 		gl.genRenderbuffers(1, &ret);
237 		gl.bindRenderbuffer(GL_RENDERBUFFER, ret);
238 
239 		if (rbo->numSamples == 0)
240 			gl.renderbufferStorage(GL_RENDERBUFFER, rbo->internalFormat.format,
241 								   rbo->width, rbo->height);
242 		else
243 			gl.renderbufferStorageMultisample(
244 				GL_RENDERBUFFER, rbo->numSamples, rbo->internalFormat.format,
245 				rbo->width, rbo->height);
246 
247 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
248 	}
249 	else if (const Texture* const tex = dynamic_cast<const Texture*>(&cfg))
250 	{
251 		gl.genTextures(1, &ret);
252 		gl.bindTexture(glTarget(*tex), ret);
253 		glInit(*tex, gl);
254 		gl.bindTexture(glTarget(*tex), 0);
255 	}
256 	else
257 		DE_ASSERT(!"Impossible image type");
258 	return ret;
259 }
260 
glDelete(const Image & cfg,GLuint img,const glw::Functions & gl)261 static void glDelete (const Image& cfg, GLuint img, const glw::Functions& gl)
262 {
263 	if (dynamic_cast<const Renderbuffer*>(&cfg) != DE_NULL)
264 		gl.deleteRenderbuffers(1, &img);
265 	else if (dynamic_cast<const Texture*>(&cfg) != DE_NULL)
266 		gl.deleteTextures(1, &img);
267 	else
268 		DE_ASSERT(!"Impossible image type");
269 }
270 
attachAttachment(const Attachment & att,GLenum attPoint,const glw::Functions & gl)271 static void attachAttachment (const Attachment& att, GLenum attPoint,
272 							  const glw::Functions& gl)
273 {
274 	if (const RenderbufferAttachment* const rAtt =
275 		dynamic_cast<const RenderbufferAttachment*>(&att))
276 		gl.framebufferRenderbuffer(rAtt->target, attPoint,
277 								   rAtt->renderbufferTarget, rAtt->imageName);
278 	else if (const TextureFlatAttachment* const fAtt =
279 			 dynamic_cast<const TextureFlatAttachment*>(&att))
280 		gl.framebufferTexture2D(fAtt->target, attPoint,
281 								fAtt->texTarget, fAtt->imageName, fAtt->level);
282 	else if (const TextureLayerAttachment* const lAtt =
283 			 dynamic_cast<const TextureLayerAttachment*>(&att))
284 		gl.framebufferTextureLayer(lAtt->target, attPoint,
285 								   lAtt->imageName, lAtt->level, lAtt->layer);
286 	else
287 		DE_ASSERT(!"Impossible attachment type");
288 }
289 
attachmentType(const Attachment & att)290 GLenum attachmentType (const Attachment& att)
291 {
292 	if (dynamic_cast<const RenderbufferAttachment*>(&att) != DE_NULL)
293 		return GL_RENDERBUFFER;
294 	else if (dynamic_cast<const TextureAttachment*>(&att) != DE_NULL)
295 		return GL_TEXTURE;
296 
297 	DE_ASSERT(!"Impossible attachment type");
298 	return GL_NONE;
299 }
300 
textureLayer(const TextureAttachment & tAtt)301 static GLsizei textureLayer (const TextureAttachment& tAtt)
302 {
303 	if (dynamic_cast<const TextureFlatAttachment*>(&tAtt) != DE_NULL)
304 		return 0;
305 	else if (const TextureLayerAttachment* const lAtt =
306 			 dynamic_cast<const TextureLayerAttachment*>(&tAtt))
307 		return lAtt->layer;
308 
309 	DE_ASSERT(!"Impossible attachment type");
310 	return 0;
311 }
312 
checkAttachmentCompleteness(Checker & cctx,const Attachment & attachment,GLenum attPoint,const Image * image,const FormatDB & db)313 static void checkAttachmentCompleteness (Checker& cctx, const Attachment& attachment,
314 										 GLenum attPoint, const Image* image,
315 										 const FormatDB& db)
316 {
317 	// GLES2 4.4.5 / GLES3 4.4.4, "Framebuffer attachment completeness"
318 
319 	if (const TextureAttachment* const texAtt =
320 		dynamic_cast<const TextureAttachment*>(&attachment))
321 		if (const TextureLayered* const ltex = dynamic_cast<const TextureLayered*>(image))
322 		{
323 			// GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
324 			// TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
325 			// three-dimensional texture, then the value of
326 			// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
327 			// of the texture.
328 			//
329 			// GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
330 			// TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
331 			// two-dimensional array texture, then the value of
332 			// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
333 			// number of layers in the texture.
334 
335 			cctx.require(textureLayer(*texAtt) < ltex->numLayers,
336 						 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
337 		}
338 
339 	// "The width and height of image are non-zero."
340 	cctx.require(image->width > 0 && image->height > 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
341 
342 	// Check for renderability
343 	FormatFlags flags = db.getFormatInfo(image->internalFormat, ANY_FORMAT);
344 	// If the format does not have the proper renderability flag, the
345 	// completeness check _must_ fail.
346 	cctx.require((flags & formatFlag(attPoint)) != 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
347 	// If the format is only optionally renderable, the completeness check _can_ fail.
348 	cctx.canRequire((flags & REQUIRED_RENDERABLE) != 0,
349 					GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
350 }
351 
352 } // namespace config
353 
354 using namespace config;
355 
require(bool condition,GLenum error)356 void Checker::require (bool condition, GLenum error)
357 {
358 	if (!condition)
359 	{
360 		m_statusCodes.erase(GL_FRAMEBUFFER_COMPLETE);
361 		m_statusCodes.insert(error);
362 	}
363 }
364 
canRequire(bool condition,GLenum error)365 void Checker::canRequire (bool condition, GLenum error)
366 {
367 	if (!condition)
368 		m_statusCodes.insert(error);
369 }
370 
FboVerifier(const FormatDB & formats,CheckerFactory & factory)371 FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory)
372 	: m_formats				(formats)
373 	, m_factory				(factory)
374 {
375 }
376 
377 /*--------------------------------------------------------------------*//*!
378  * \brief Return acceptable framebuffer status codes.
379  *
380  * This function examines the framebuffer configuration descriptor `fboConfig`
381  * and returns the set of status codes that `glCheckFramebufferStatus` is
382  * allowed to return on a conforming implementation when given a framebuffer
383  * whose configuration adheres to `fboConfig`.
384  *
385  * The returned set is guaranteed to be non-empty, but it may contain multiple
386  * INCOMPLETE statuses (if there are multiple errors in the spec), or or a mix
387  * of COMPLETE and INCOMPLETE statuses (if supporting a FBO with this spec is
388  * optional). Furthermore, the statuses may contain GL error codes, which
389  * indicate that trying to create a framebuffer configuration like this could
390  * have failed with an error (if one was checked for) even before
391  * `glCheckFramebufferStatus` was ever called.
392  *
393  *//*--------------------------------------------------------------------*/
validStatusCodes(const Framebuffer & fboConfig) const394 StatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const
395 {
396 	const AttachmentMap& atts = fboConfig.attachments;
397 	const UniquePtr<Checker> cctx(m_factory.createChecker());
398 
399 	for (TextureMap::const_iterator it = fboConfig.textures.begin();
400 		 it != fboConfig.textures.end(); it++)
401 	{
402 		const FormatFlags flags =
403 			m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
404 		cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_ENUM);
405 		cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_OPERATION);
406 		cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_VALUE);
407 	}
408 
409 	for (RboMap::const_iterator it = fboConfig.rbos.begin(); it != fboConfig.rbos.end(); it++)
410 	{
411 		const FormatFlags flags =
412 			m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
413 		cctx->require((flags & RENDERBUFFER_VALID) != 0, GL_INVALID_ENUM);
414 	}
415 
416 	// "There is at least one image attached to the framebuffer."
417 	// TODO: support XXX_framebuffer_no_attachments
418 	cctx->require(!atts.empty(), GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
419 
420 	for (AttachmentMap::const_iterator it = atts.begin(); it != atts.end(); it++)
421 	{
422 		const GLenum attPoint = it->first;
423 		const Attachment& att = *it->second;
424 		const Image* const image = fboConfig.getImage(attachmentType(att), att.imageName);
425 		checkAttachmentCompleteness(*cctx, att, attPoint, image, m_formats);
426 		cctx->check(it->first, *it->second, image);
427 	}
428 
429 	return cctx->getStatusCodes();
430 }
431 
432 
attach(glw::GLenum attPoint,const Attachment * att)433 void Framebuffer::attach (glw::GLenum attPoint, const Attachment* att)
434 {
435 	if (att == DE_NULL)
436 		attachments.erase(attPoint);
437 	else
438 		attachments[attPoint] = att;
439 }
440 
getImage(GLenum type,glw::GLuint imgName) const441 const Image* Framebuffer::getImage (GLenum type, glw::GLuint imgName) const
442 {
443 	switch (type)
444 	{
445 		case GL_TEXTURE:
446 			return lookupDefault(textures, imgName, DE_NULL);
447 		case GL_RENDERBUFFER:
448 			return lookupDefault(rbos, imgName, DE_NULL);
449 		default:
450 			DE_ASSERT(!"Bad image type");
451 	}
452 	return DE_NULL; // shut up compiler warning
453 }
454 
setTexture(glw::GLuint texName,const Texture & texCfg)455 void Framebuffer::setTexture (glw::GLuint texName, const Texture& texCfg)
456 {
457 	textures[texName] = &texCfg;
458 }
459 
setRbo(glw::GLuint rbName,const Renderbuffer & rbCfg)460 void Framebuffer::setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg)
461 {
462 	rbos[rbName] = &rbCfg;
463 }
464 
logField(TestLog & log,const string & field,const string & value)465 static void logField (TestLog& log, const string& field, const string& value)
466 {
467 	log << TestLog::Message << field << ": " << value << TestLog::EndMessage;
468 }
469 
logImage(const Image & img,TestLog & log,bool useType)470 static void logImage (const Image& img, TestLog& log, bool useType)
471 {
472 	const GLenum type = img.internalFormat.unsizedType;
473 	logField(log, "Internal format",	getPixelFormatName(img.internalFormat.format));
474 	if (useType && type != GL_NONE)
475 		logField(log, "Format type",	getTypeName(type));
476 	logField(log, "Width", 				toString(img.width));
477 	logField(log, "Height",				toString(img.height));
478 }
479 
logRenderbuffer(const Renderbuffer & rbo,TestLog & log)480 static void logRenderbuffer (const Renderbuffer& rbo, TestLog& log)
481 {
482 	logImage(rbo, log, false);
483 	logField(log, "Samples",			toString(rbo.numSamples));
484 }
485 
logTexture(const Texture & tex,TestLog & log)486 static void logTexture (const Texture& tex, TestLog& log)
487 {
488 	logField(log, "Type",				glu::getTextureTargetName(glTarget(tex)));
489 	logImage(tex, log, true);
490 	logField(log, "Levels",				toString(tex.numLevels));
491 	if (const TextureLayered* const lTex = dynamic_cast<const TextureLayered*>(&tex))
492 		logField(log, "Layers",				toString(lTex->numLayers));
493 }
494 
logAttachment(const Attachment & att,TestLog & log)495 static void logAttachment (const Attachment& att, TestLog& log)
496 {
497 	logField(log, "Target",				getFramebufferTargetName(att.target));
498 	logField(log, "Type",				getFramebufferAttachmentTypeName(attachmentType(att)));
499 	logField(log, "Image Name",			toString(att.imageName));
500 	if (const RenderbufferAttachment* const rAtt
501 		= dynamic_cast<const RenderbufferAttachment*>(&att))
502 	{
503 		DE_UNREF(rAtt); // To shut up compiler during optimized builds.
504 		DE_ASSERT(rAtt->renderbufferTarget == GL_RENDERBUFFER);
505 		logField(log, "Renderbuffer Target",	"GL_RENDERBUFFER");
506 	}
507 	else if (const TextureAttachment* const tAtt = dynamic_cast<const TextureAttachment*>(&att))
508 	{
509 		logField(log, "Mipmap Level",		toString(tAtt->level));
510 		if (const TextureFlatAttachment* const fAtt =
511 			dynamic_cast<const TextureFlatAttachment*>(tAtt))
512 			logField(log, "Texture Target",		getTextureTargetName(fAtt->texTarget));
513 		else if (const TextureLayerAttachment* const lAtt =
514 			dynamic_cast<const TextureLayerAttachment*>(tAtt))
515 			logField(log, "Layer",				toString(lAtt->level));
516 	}
517 }
518 
logFramebufferConfig(const Framebuffer & cfg,TestLog & log)519 void logFramebufferConfig (const Framebuffer& cfg, TestLog& log)
520 {
521 	log << TestLog::Section("Framebuffer", "Framebuffer configuration");
522 
523 	const string rboDesc = cfg.rbos.empty()
524 		? "No renderbuffers were created"
525 		: "Renderbuffers created";
526 	log << TestLog::Section("Renderbuffers", rboDesc);
527 	for (RboMap::const_iterator it = cfg.rbos.begin(); it != cfg.rbos.end(); ++it)
528 	{
529 		const string num = toString(it->first);
530 		log << TestLog::Section(num, "Renderbuffer " + num);
531 		logRenderbuffer(*it->second, log);
532 		log << TestLog::EndSection;
533 	}
534 	log << TestLog::EndSection; // Renderbuffers
535 
536 	const string texDesc = cfg.textures.empty()
537 		? "No textures were created"
538 		: "Textures created";
539 	log << TestLog::Section("Textures", texDesc);
540 	for (TextureMap::const_iterator it = cfg.textures.begin();
541 		 it != cfg.textures.end(); ++it)
542 	{
543 		const string num = toString(it->first);
544 		log << TestLog::Section(num, "Texture " + num);
545 		logTexture(*it->second, log);
546 		log << TestLog::EndSection;
547 	}
548 	log << TestLog::EndSection; // Textures
549 
550 	const string attDesc = cfg.attachments.empty()
551 		? "Framebuffer has no attachments"
552 		: "Framebuffer attachments";
553 	log << TestLog::Section("Attachments", attDesc);
554 	for (AttachmentMap::const_iterator it = cfg.attachments.begin();
555 		 it != cfg.attachments.end(); it++)
556 	{
557 		const string attPointName = getFramebufferAttachmentName(it->first);
558 		log << TestLog::Section(attPointName, "Attachment point " + attPointName);
559 		logAttachment(*it->second, log);
560 		log << TestLog::EndSection;
561 	}
562 	log << TestLog::EndSection; // Attachments
563 
564 	log << TestLog::EndSection; // Framebuffer
565 }
566 
FboBuilder(GLuint fbo,GLenum target,const glw::Functions & gl)567 FboBuilder::FboBuilder (GLuint fbo, GLenum target, const glw::Functions& gl)
568 	: m_error	(GL_NO_ERROR)
569 	, m_target	(target)
570 	, m_gl		(gl)
571 {
572 	m_gl.bindFramebuffer(m_target, fbo);
573 }
574 
~FboBuilder(void)575 FboBuilder::~FboBuilder (void)
576 {
577 	for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++)
578 	{
579 		glDelete(*it->second, it->first, m_gl);
580 	}
581 	for (RboMap::const_iterator it = rbos.begin(); it != rbos.end(); it++)
582 	{
583 		glDelete(*it->second, it->first, m_gl);
584 	}
585 	m_gl.bindFramebuffer(m_target, 0);
586 	for (Configs::const_iterator it = m_configs.begin(); it != m_configs.end(); it++)
587 	{
588 		delete *it;
589 	}
590 }
591 
checkError(void)592 void FboBuilder::checkError (void)
593 {
594 	const GLenum error = m_gl.getError();
595 	if (error != GL_NO_ERROR && m_error == GL_NO_ERROR)
596 		m_error = error;
597 }
598 
glAttach(GLenum attPoint,const Attachment * att)599 void FboBuilder::glAttach (GLenum attPoint, const Attachment* att)
600 {
601 	if (att == NULL)
602 		m_gl.framebufferRenderbuffer(m_target, attPoint, GL_RENDERBUFFER, 0);
603 	else
604 		attachAttachment(*att, attPoint, m_gl);
605 	checkError();
606 	attach(attPoint, att);
607 }
608 
glCreateTexture(const Texture & texCfg)609 GLuint FboBuilder::glCreateTexture (const Texture& texCfg)
610 {
611 	const GLuint texName = glCreate(texCfg, m_gl);
612 	checkError();
613 	setTexture(texName, texCfg);
614 	return texName;
615 }
616 
glCreateRbo(const Renderbuffer & rbCfg)617 GLuint FboBuilder::glCreateRbo (const Renderbuffer& rbCfg)
618 {
619 	const GLuint rbName = glCreate(rbCfg, m_gl);
620 	checkError();
621 	setRbo(rbName, rbCfg);
622 	return rbName;
623 }
624 
transferImageFormat(const ImageFormat & imgFormat)625 TransferFormat transferImageFormat (const ImageFormat& imgFormat)
626 {
627 	if (imgFormat.unsizedType == GL_NONE)
628 		return getTransferFormat(mapGLInternalFormat(imgFormat.format));
629 	else
630 		return TransferFormat(imgFormat.format, imgFormat.unsizedType);
631 }
632 
633 } // FboUtil
634 } // gls
635 } // deqp
636