1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Utilities for framebuffer objects.
22 *//*--------------------------------------------------------------------*/
24 #include "glsFboUtil.hpp"
26 #include "glwEnums.hpp"
27 #include "deUniquePtr.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluStrUtil.hpp"
30 #include "deStringUtil.hpp"
31 #include "deSTLUtil.hpp"
36 using tcu::TextureFormat;
37 using tcu::NotSupportedError;
38 using glu::TransferFormat;
39 using glu::mapGLInternalFormat;
40 using glu::mapGLTransferFormat;
41 using glu::getPixelFormatName;
42 using glu::getTypeName;
43 using glu::getFramebufferTargetName;
44 using glu::getFramebufferAttachmentName;
45 using glu::getFramebufferAttachmentTypeName;
46 using glu::getTextureTargetName;
47 using glu::getTransferFormat;
48 using glu::ContextInfo;
49 using glu::ContextType;
50 using glu::RenderContext;
56 using std::istringstream;
57 using std::istream_iterator;
68 static bool isFramebufferStatus (glw::GLenum fboStatus)
70 return glu::getFramebufferStatusName(fboStatus) != DE_NULL;
73 static bool isErrorCode (glw::GLenum errorCode)
75 return glu::getErrorName(errorCode) != DE_NULL;
79 std::ostream& operator<< (std::ostream& stream, const ImageFormat& format)
81 if (format.unsizedType == GL_NONE)
84 return stream << glu::getPixelFormatStr(format.format);
89 return stream << "(format = " << glu::getPixelFormatStr(format.format) << ", type = " << glu::getTypeStr(format.unsizedType) << ")";
93 void FormatDB::addCoreFormat (ImageFormat format, FormatFlags newFlags)
95 FormatFlags& flags = m_formatFlags[format];
96 flags = FormatFlags(flags | newFlags);
99 void FormatDB::addExtensionFormat (ImageFormat format, FormatFlags newFlags, const std::set<std::string>& requiredExtensions)
101 DE_ASSERT(!requiredExtensions.empty());
104 FormatFlags& flags = m_formatFlags[format];
105 flags = FormatFlags(flags | newFlags);
109 std::set<ExtensionInfo>& extensionInfo = m_formatExtensions[format];
110 ExtensionInfo extensionRecord;
112 extensionRecord.flags = newFlags;
113 extensionRecord.requiredExtensions = requiredExtensions;
115 DE_ASSERT(!de::contains(extensionInfo, extensionRecord)); // extensions specified only once
116 extensionInfo.insert(extensionRecord);
120 // Not too fast at the moment, might consider indexing?
121 Formats FormatDB::getFormats (FormatFlags requirements) const
124 for (FormatMap::const_iterator it = m_formatFlags.begin(); it != m_formatFlags.end(); it++)
126 if ((it->second & requirements) == requirements)
127 ret.insert(it->first);
132 bool FormatDB::isKnownFormat (ImageFormat format) const
134 return de::contains(m_formatFlags, format);
137 FormatFlags FormatDB::getFormatInfo (ImageFormat format) const
139 DE_ASSERT(de::contains(m_formatFlags, format));
140 return de::lookup(m_formatFlags, format);
143 std::set<std::set<std::string> > FormatDB::getFormatFeatureExtensions (ImageFormat format, FormatFlags requirements) const
145 DE_ASSERT(de::contains(m_formatExtensions, format));
147 const std::set<ExtensionInfo>& extensionInfo = de::lookup(m_formatExtensions, format);
148 std::set<std::set<std::string> > ret;
150 for (std::set<ExtensionInfo>::const_iterator it = extensionInfo.begin(); it != extensionInfo.end(); ++it)
152 if ((it->flags & requirements) == requirements)
153 ret.insert(it->requiredExtensions);
159 bool FormatDB::ExtensionInfo::operator< (const ExtensionInfo& other) const
161 return (requiredExtensions < other.requiredExtensions) ||
162 ((requiredExtensions == other.requiredExtensions) && (flags < other.flags));
165 static bool detectGLESCompatibleContext (const RenderContext& ctx, int requiredMajor, int requiredMinor)
167 const glw::Functions& gl = ctx.getFunctions();
168 glw::GLint majorVersion = 0;
169 glw::GLint minorVersion = 0;
171 // Detect compatible GLES context by querying GL_MAJOR_VERSION.
172 // This query does not exist on GLES2 so a failing query implies
175 gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
176 if (gl.getError() != GL_NO_ERROR)
179 gl.getIntegerv(GL_MINOR_VERSION, &minorVersion);
180 if (gl.getError() != GL_NO_ERROR)
183 return (majorVersion > requiredMajor) || (majorVersion == requiredMajor && minorVersion >= requiredMinor);
186 static bool checkExtensionSupport (const ContextInfo& ctxInfo, const RenderContext& ctx, const std::string& extension)
188 if (de::beginsWith(extension, "GL_"))
189 return ctxInfo.isExtensionSupported(extension.c_str());
190 else if (extension == "DEQP_gles3_core_compatible")
191 return detectGLESCompatibleContext(ctx, 3, 0);
192 else if (extension == "DEQP_gles31_core_compatible")
193 return detectGLESCompatibleContext(ctx, 3, 1);
201 bool checkExtensionSupport (const RenderContext& ctx, const std::string& extension)
203 const de::UniquePtr<ContextInfo> info(ContextInfo::create(ctx));
204 return checkExtensionSupport(*info, ctx, extension);
207 std::string getExtensionDescription (const std::string& extension)
209 if (de::beginsWith(extension, "GL_"))
211 else if (extension == "DEQP_gles3_core_compatible")
212 return "GLES3 compatible context";
213 else if (extension == "DEQP_gles31_core_compatible")
214 return "GLES3.1 compatible context";
222 void addFormats (FormatDB& db, FormatEntries stdFmts)
224 for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++)
226 for (const FormatKey* it2 = it->second.begin(); it2 != it->second.end(); it2++)
227 db.addCoreFormat(formatKeyInfo(*it2), it->first);
231 void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const RenderContext* ctx)
233 const UniquePtr<ContextInfo> ctxInfo(ctx != DE_NULL ? ContextInfo::create(*ctx) : DE_NULL);
234 for (const FormatExtEntry* entryIt = extFmts.begin(); entryIt != extFmts.end(); entryIt++)
236 bool supported = true;
237 std::set<std::string> requiredExtensions;
239 // parse required extensions
241 istringstream tokenStream(string(entryIt->extensions));
242 istream_iterator<string> tokens((tokenStream)), end;
244 while (tokens != end)
246 requiredExtensions.insert(*tokens);
254 for (std::set<std::string>::const_iterator extIt = requiredExtensions.begin(); extIt != requiredExtensions.end(); ++extIt)
256 if (!checkExtensionSupport(*ctxInfo, *ctx, *extIt))
265 for (const FormatKey* i2 = entryIt->formats.begin(); i2 != entryIt->formats.end(); i2++)
266 db.addExtensionFormat(formatKeyInfo(*i2), FormatFlags(entryIt->flags), requiredExtensions);
270 FormatFlags formatFlag (GLenum context)
275 return FormatFlags(0);
276 case GL_RENDERBUFFER:
277 return RENDERBUFFER_VALID;
279 return TEXTURE_VALID;
280 case GL_STENCIL_ATTACHMENT:
281 return STENCIL_RENDERABLE;
282 case GL_DEPTH_ATTACHMENT:
283 return DEPTH_RENDERABLE;
285 DE_ASSERT(context >= GL_COLOR_ATTACHMENT0 && context <= GL_COLOR_ATTACHMENT15);
286 return COLOR_RENDERABLE;
290 static FormatFlags getAttachmentRenderabilityFlag (GLenum attachment)
294 case GL_STENCIL_ATTACHMENT: return STENCIL_RENDERABLE;
295 case GL_DEPTH_ATTACHMENT: return DEPTH_RENDERABLE;
298 DE_ASSERT(attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15);
299 return COLOR_RENDERABLE;
305 GLsizei imageNumSamples (const Image& img)
307 if (const Renderbuffer* rbo = dynamic_cast<const Renderbuffer*>(&img))
308 return rbo->numSamples;
312 static GLenum glTarget (const Image& img)
314 if (dynamic_cast<const Renderbuffer*>(&img) != DE_NULL)
315 return GL_RENDERBUFFER;
316 if (dynamic_cast<const Texture2D*>(&img) != DE_NULL)
317 return GL_TEXTURE_2D;
318 if (dynamic_cast<const TextureCubeMap*>(&img) != DE_NULL)
319 return GL_TEXTURE_CUBE_MAP;
320 if (dynamic_cast<const Texture3D*>(&img) != DE_NULL)
321 return GL_TEXTURE_3D;
322 if (dynamic_cast<const Texture2DArray*>(&img) != DE_NULL)
323 return GL_TEXTURE_2D_ARRAY;
325 DE_ASSERT(!"Impossible image type");
329 static void glInitFlat (const TextureFlat& cfg, GLenum target, const glw::Functions& gl)
331 const TransferFormat format = transferImageFormat(cfg.internalFormat);
333 GLint h = cfg.height;
334 for (GLint level = 0; level < cfg.numLevels; level++)
336 gl.texImage2D(target, level, cfg.internalFormat.format, w, h, 0,
337 format.format, format.dataType, DE_NULL);
338 w = de::max(1, w / 2);
339 h = de::max(1, h / 2);
343 static void glInitLayered (const TextureLayered& cfg,
344 GLint depth_divider, const glw::Functions& gl)
346 const TransferFormat format = transferImageFormat(cfg.internalFormat);
348 GLint h = cfg.height;
349 GLint depth = cfg.numLayers;
350 for (GLint level = 0; level < cfg.numLevels; level++)
352 gl.texImage3D(glTarget(cfg), level, cfg.internalFormat.format, w, h, depth, 0,
353 format.format, format.dataType, DE_NULL);
354 w = de::max(1, w / 2);
355 h = de::max(1, h / 2);
356 depth = de::max(1, depth / depth_divider);
360 static void glInit (const Texture& cfg, const glw::Functions& gl)
362 if (const Texture2D* t2d = dynamic_cast<const Texture2D*>(&cfg))
363 glInitFlat(*t2d, glTarget(*t2d), gl);
364 else if (const TextureCubeMap* tcm = dynamic_cast<const TextureCubeMap*>(&cfg))
366 // \todo [2013-12-05 lauri]
367 // move this to glu or someplace sensible (this array is already
368 // present in duplicates)
369 static const GLenum s_cubeMapFaces[] =
371 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
372 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
373 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
374 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
375 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
376 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
378 const Range<GLenum> range = GLS_ARRAY_RANGE(s_cubeMapFaces);
379 for (const GLenum* it = range.begin(); it != range.end(); it++)
380 glInitFlat(*tcm, *it, gl);
382 else if (const Texture3D* t3d = dynamic_cast<const Texture3D*>(&cfg))
383 glInitLayered(*t3d, 2, gl);
384 else if (const Texture2DArray* t2a = dynamic_cast<const Texture2DArray*>(&cfg))
385 glInitLayered(*t2a, 1, gl);
388 static GLuint glCreate (const Image& cfg, const glw::Functions& gl)
391 if (const Renderbuffer* const rbo = dynamic_cast<const Renderbuffer*>(&cfg))
393 gl.genRenderbuffers(1, &ret);
394 gl.bindRenderbuffer(GL_RENDERBUFFER, ret);
396 if (rbo->numSamples == 0)
397 gl.renderbufferStorage(GL_RENDERBUFFER, rbo->internalFormat.format,
398 rbo->width, rbo->height);
400 gl.renderbufferStorageMultisample(
401 GL_RENDERBUFFER, rbo->numSamples, rbo->internalFormat.format,
402 rbo->width, rbo->height);
404 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
406 else if (const Texture* const tex = dynamic_cast<const Texture*>(&cfg))
408 gl.genTextures(1, &ret);
409 gl.bindTexture(glTarget(*tex), ret);
411 gl.bindTexture(glTarget(*tex), 0);
414 DE_ASSERT(!"Impossible image type");
418 static void glDelete (const Image& cfg, GLuint img, const glw::Functions& gl)
420 if (dynamic_cast<const Renderbuffer*>(&cfg) != DE_NULL)
421 gl.deleteRenderbuffers(1, &img);
422 else if (dynamic_cast<const Texture*>(&cfg) != DE_NULL)
423 gl.deleteTextures(1, &img);
425 DE_ASSERT(!"Impossible image type");
428 static void attachAttachment (const Attachment& att, GLenum attPoint,
429 const glw::Functions& gl)
431 if (const RenderbufferAttachment* const rAtt =
432 dynamic_cast<const RenderbufferAttachment*>(&att))
433 gl.framebufferRenderbuffer(rAtt->target, attPoint,
434 rAtt->renderbufferTarget, rAtt->imageName);
435 else if (const TextureFlatAttachment* const fAtt =
436 dynamic_cast<const TextureFlatAttachment*>(&att))
437 gl.framebufferTexture2D(fAtt->target, attPoint,
438 fAtt->texTarget, fAtt->imageName, fAtt->level);
439 else if (const TextureLayerAttachment* const lAtt =
440 dynamic_cast<const TextureLayerAttachment*>(&att))
441 gl.framebufferTextureLayer(lAtt->target, attPoint,
442 lAtt->imageName, lAtt->level, lAtt->layer);
444 DE_ASSERT(!"Impossible attachment type");
447 GLenum attachmentType (const Attachment& att)
449 if (dynamic_cast<const RenderbufferAttachment*>(&att) != DE_NULL)
450 return GL_RENDERBUFFER;
451 else if (dynamic_cast<const TextureAttachment*>(&att) != DE_NULL)
454 DE_ASSERT(!"Impossible attachment type");
458 static GLsizei textureLayer (const TextureAttachment& tAtt)
460 if (dynamic_cast<const TextureFlatAttachment*>(&tAtt) != DE_NULL)
462 else if (const TextureLayerAttachment* const lAtt =
463 dynamic_cast<const TextureLayerAttachment*>(&tAtt))
466 DE_ASSERT(!"Impossible attachment type");
470 static void checkAttachmentCompleteness (Checker& cctx, const Attachment& attachment,
471 GLenum attPoint, const Image* image,
474 // GLES2 4.4.5 / GLES3 4.4.4, "Framebuffer attachment completeness"
476 if (const TextureAttachment* const texAtt =
477 dynamic_cast<const TextureAttachment*>(&attachment))
478 if (const TextureLayered* const ltex = dynamic_cast<const TextureLayered*>(image))
480 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
481 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
482 // three-dimensional texture, then the value of
483 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
486 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
487 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
488 // two-dimensional array texture, then the value of
489 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
490 // number of layers in the texture.
492 if (textureLayer(*texAtt) >= ltex->numLayers)
493 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attached layer index is larger than present");
496 // "The width and height of image are non-zero."
497 if (image->width == 0 || image->height == 0)
498 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Width and height of an image are not non-zero");
500 // Check for renderability
501 if (db.isKnownFormat(image->internalFormat))
503 const FormatFlags flags = db.getFormatInfo(image->internalFormat);
505 // If the format does not have the proper renderability flag, the
506 // completeness check _must_ fail.
507 if ((flags & getAttachmentRenderabilityFlag(attPoint)) == 0)
508 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not renderable in this attachment");
509 // If the format is only optionally renderable, the completeness check _can_ fail.
510 else if ((flags & REQUIRED_RENDERABLE) == 0)
511 cctx.addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not required renderable");
514 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not legal");
517 } // namespace config
519 using namespace config;
521 Checker::Checker (const glu::RenderContext& ctx)
524 m_statusCodes.setAllowComplete(true);
527 void Checker::addGLError (glw::GLenum error, const char* description)
529 m_statusCodes.addErrorCode(error, description);
530 m_statusCodes.setAllowComplete(false);
533 void Checker::addPotentialGLError (glw::GLenum error, const char* description)
535 m_statusCodes.addErrorCode(error, description);
538 void Checker::addFBOStatus (GLenum status, const char* description)
540 m_statusCodes.addFBOErrorStatus(status, description);
541 m_statusCodes.setAllowComplete(false);
544 void Checker::addPotentialFBOStatus (GLenum status, const char* description)
546 m_statusCodes.addFBOErrorStatus(status, description);
549 FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory, const glu::RenderContext& renderCtx)
550 : m_formats (formats)
551 , m_factory (factory)
552 , m_renderCtx (renderCtx)
556 /*--------------------------------------------------------------------*//*!
557 * \brief Return acceptable framebuffer status codes.
559 * This function examines the framebuffer configuration descriptor `fboConfig`
560 * and returns the set of status codes that `glCheckFramebufferStatus` is
561 * allowed to return on a conforming implementation when given a framebuffer
562 * whose configuration adheres to `fboConfig`.
564 * The returned set is guaranteed to be non-empty, but it may contain multiple
565 * INCOMPLETE statuses (if there are multiple errors in the spec), or or a mix
566 * of COMPLETE and INCOMPLETE statuses (if supporting a FBO with this spec is
567 * optional). Furthermore, the statuses may contain GL error codes, which
568 * indicate that trying to create a framebuffer configuration like this could
569 * have failed with an error (if one was checked for) even before
570 * `glCheckFramebufferStatus` was ever called.
572 *//*--------------------------------------------------------------------*/
573 ValidStatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const
575 const AttachmentMap& atts = fboConfig.attachments;
576 const UniquePtr<Checker> cctx(m_factory.createChecker(m_renderCtx));
578 for (TextureMap::const_iterator it = fboConfig.textures.begin();
579 it != fboConfig.textures.end(); it++)
581 std::string errorDescription;
583 if (m_formats.isKnownFormat(it->second->internalFormat))
585 const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat);
587 if ((flags & TEXTURE_VALID) == 0)
588 errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a texture";
590 else if (it->second->internalFormat.unsizedType == GL_NONE)
593 errorDescription = "Format " + de::toString(it->second->internalFormat) + " does not exist";
597 // unsized type-format pair
598 errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a legal format";
601 if (!errorDescription.empty())
603 cctx->addGLError(GL_INVALID_ENUM, errorDescription.c_str());
604 cctx->addGLError(GL_INVALID_OPERATION, errorDescription.c_str());
605 cctx->addGLError(GL_INVALID_VALUE, errorDescription.c_str());
609 for (RboMap::const_iterator it = fboConfig.rbos.begin(); it != fboConfig.rbos.end(); it++)
611 if (m_formats.isKnownFormat(it->second->internalFormat))
613 const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat);
614 if ((flags & RENDERBUFFER_VALID) == 0)
616 const std::string reason = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a renderbuffer";
617 cctx->addGLError(GL_INVALID_ENUM, reason.c_str());
622 const std::string reason = "Internal format " + de::toString(it->second->internalFormat) + " does not exist";
623 cctx->addGLError(GL_INVALID_ENUM, reason.c_str());
627 // "There is at least one image attached to the framebuffer."
628 // \todo support XXX_framebuffer_no_attachments
630 cctx->addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, "No images attached to the framebuffer");
632 for (AttachmentMap::const_iterator it = atts.begin(); it != atts.end(); it++)
634 const GLenum attPoint = it->first;
635 const Attachment& att = *it->second;
636 const Image* const image = fboConfig.getImage(attachmentType(att), att.imageName);
638 checkAttachmentCompleteness(*cctx, att, attPoint, image, m_formats);
639 cctx->check(it->first, *it->second, image);
642 return cctx->getStatusCodes();
646 void Framebuffer::attach (glw::GLenum attPoint, const Attachment* att)
649 attachments.erase(attPoint);
651 attachments[attPoint] = att;
654 const Image* Framebuffer::getImage (GLenum type, glw::GLuint imgName) const
659 return de::lookupDefault(textures, imgName, DE_NULL);
660 case GL_RENDERBUFFER:
661 return de::lookupDefault(rbos, imgName, DE_NULL);
663 DE_ASSERT(!"Bad image type");
665 return DE_NULL; // shut up compiler warning
668 void Framebuffer::setTexture (glw::GLuint texName, const Texture& texCfg)
670 textures[texName] = &texCfg;
673 void Framebuffer::setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg)
675 rbos[rbName] = &rbCfg;
678 static void logField (TestLog& log, const string& field, const string& value)
680 log << TestLog::Message << field << ": " << value << TestLog::EndMessage;
683 static void logImage (const Image& img, TestLog& log, bool useType)
685 const GLenum type = img.internalFormat.unsizedType;
686 logField(log, "Internal format", getPixelFormatName(img.internalFormat.format));
687 if (useType && type != GL_NONE)
688 logField(log, "Format type", getTypeName(type));
689 logField(log, "Width", toString(img.width));
690 logField(log, "Height", toString(img.height));
693 static void logRenderbuffer (const Renderbuffer& rbo, TestLog& log)
695 logImage(rbo, log, false);
696 logField(log, "Samples", toString(rbo.numSamples));
699 static void logTexture (const Texture& tex, TestLog& log)
701 logField(log, "Type", glu::getTextureTargetName(glTarget(tex)));
702 logImage(tex, log, true);
703 logField(log, "Levels", toString(tex.numLevels));
704 if (const TextureLayered* const lTex = dynamic_cast<const TextureLayered*>(&tex))
705 logField(log, "Layers", toString(lTex->numLayers));
708 static void logAttachment (const Attachment& att, TestLog& log)
710 logField(log, "Target", getFramebufferTargetName(att.target));
711 logField(log, "Type", getFramebufferAttachmentTypeName(attachmentType(att)));
712 logField(log, "Image Name", toString(att.imageName));
713 if (const RenderbufferAttachment* const rAtt
714 = dynamic_cast<const RenderbufferAttachment*>(&att))
716 DE_UNREF(rAtt); // To shut up compiler during optimized builds.
717 DE_ASSERT(rAtt->renderbufferTarget == GL_RENDERBUFFER);
718 logField(log, "Renderbuffer Target", "GL_RENDERBUFFER");
720 else if (const TextureAttachment* const tAtt = dynamic_cast<const TextureAttachment*>(&att))
722 logField(log, "Mipmap Level", toString(tAtt->level));
723 if (const TextureFlatAttachment* const fAtt =
724 dynamic_cast<const TextureFlatAttachment*>(tAtt))
725 logField(log, "Texture Target", getTextureTargetName(fAtt->texTarget));
726 else if (const TextureLayerAttachment* const lAtt =
727 dynamic_cast<const TextureLayerAttachment*>(tAtt))
728 logField(log, "Layer", toString(lAtt->level));
732 void logFramebufferConfig (const Framebuffer& cfg, TestLog& log)
734 log << TestLog::Section("Framebuffer", "Framebuffer configuration");
736 for (RboMap::const_iterator it = cfg.rbos.begin(); it != cfg.rbos.end(); ++it)
738 const string num = toString(it->first);
739 const tcu::ScopedLogSection subsection (log, num, "Renderbuffer " + num);
741 logRenderbuffer(*it->second, log);
744 for (TextureMap::const_iterator it = cfg.textures.begin();
745 it != cfg.textures.end(); ++it)
747 const string num = toString(it->first);
748 const tcu::ScopedLogSection subsection (log, num, "Texture " + num);
750 logTexture(*it->second, log);
753 const string attDesc = cfg.attachments.empty()
754 ? "Framebuffer has no attachments"
755 : "Framebuffer attachments";
756 log << TestLog::Section("Attachments", attDesc);
757 for (AttachmentMap::const_iterator it = cfg.attachments.begin();
758 it != cfg.attachments.end(); it++)
760 const string attPointName = getFramebufferAttachmentName(it->first);
761 log << TestLog::Section(attPointName, "Attachment point " + attPointName);
762 logAttachment(*it->second, log);
763 log << TestLog::EndSection;
765 log << TestLog::EndSection; // Attachments
767 log << TestLog::EndSection; // Framebuffer
770 ValidStatusCodes::ValidStatusCodes (void)
771 : m_allowComplete(false)
775 bool ValidStatusCodes::isFBOStatusValid (glw::GLenum fboStatus) const
777 if (fboStatus == GL_FRAMEBUFFER_COMPLETE)
778 return m_allowComplete;
781 // rule violation exists?
782 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
784 if (m_errorStatuses[ndx].errorCode == fboStatus)
791 bool ValidStatusCodes::isFBOStatusRequired (glw::GLenum fboStatus) const
793 if (fboStatus == GL_FRAMEBUFFER_COMPLETE)
794 return m_allowComplete && m_errorStatuses.empty();
796 // fboStatus is the only allowed error status and succeeding is forbidden
797 return !m_allowComplete && m_errorStatuses.size() == 1 && m_errorStatuses.front().errorCode == fboStatus;
800 bool ValidStatusCodes::isErrorCodeValid (glw::GLenum errorCode) const
802 if (errorCode == GL_NO_ERROR)
803 return m_errorCodes.empty();
806 // rule violation exists?
807 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
809 if (m_errorCodes[ndx].errorCode == errorCode)
816 bool ValidStatusCodes::isErrorCodeRequired (glw::GLenum errorCode) const
818 if (m_errorCodes.empty() && errorCode == GL_NO_ERROR)
821 // only this error code listed
822 return m_errorCodes.size() == 1 && m_errorCodes.front().errorCode == errorCode;
825 void ValidStatusCodes::addErrorCode (glw::GLenum error, const char* description)
827 DE_ASSERT(isErrorCode(error));
828 DE_ASSERT(error != GL_NO_ERROR);
829 addViolation(m_errorCodes, error, description);
832 void ValidStatusCodes::addFBOErrorStatus (glw::GLenum status, const char* description)
834 DE_ASSERT(isFramebufferStatus(status));
835 DE_ASSERT(status != GL_FRAMEBUFFER_COMPLETE);
836 addViolation(m_errorStatuses, status, description);
839 void ValidStatusCodes::setAllowComplete (bool b)
844 void ValidStatusCodes::logLegalResults (tcu::TestLog& log) const
846 tcu::MessageBuilder msg (&log);
847 std::vector<std::string> validResults;
849 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
850 validResults.push_back(std::string(glu::getErrorName(m_errorCodes[ndx].errorCode)) + " (during FBO initialization)");
852 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
853 validResults.push_back(glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode));
856 validResults.push_back("GL_FRAMEBUFFER_COMPLETE");
859 if (validResults.size() > 1)
862 for (int ndx = 0; ndx < (int)validResults.size(); ++ndx)
864 const bool last = ((ndx + 1) == (int)validResults.size());
865 const bool secondToLast = ((ndx + 2) == (int)validResults.size());
867 msg << validResults[ndx];
869 msg << ((secondToLast) ? (" or ") : (", "));
872 msg << "." << TestLog::EndMessage;
875 void ValidStatusCodes::logRules (tcu::TestLog& log) const
877 const tcu::ScopedLogSection section(log, "Rules", "Active rules");
879 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx)
880 logRule(log, glu::getErrorName(m_errorCodes[ndx].errorCode), m_errorCodes[ndx].rules);
882 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx)
883 logRule(log, glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode), m_errorStatuses[ndx].rules);
887 std::set<std::string> defaultRule;
888 defaultRule.insert("FBO is complete");
889 logRule(log, "GL_FRAMEBUFFER_COMPLETE", defaultRule);
893 void ValidStatusCodes::logRule (tcu::TestLog& log, const std::string& ruleName, const std::set<std::string>& rules) const
897 const tcu::ScopedLogSection section (log, ruleName, ruleName);
898 tcu::MessageBuilder msg (&log);
901 for (std::set<std::string>::const_iterator it = rules.begin(); it != rules.end(); ++it)
902 msg << "\t * " << *it << "\n";
903 msg << TestLog::EndMessage;
907 void ValidStatusCodes::addViolation (std::vector<RuleViolation>& dst, glw::GLenum code, const char* description) const
909 // rule violation already exists?
910 for (int ndx = 0; ndx < (int)dst.size(); ++ndx)
912 if (dst[ndx].errorCode == code)
914 dst[ndx].rules.insert(std::string(description));
921 RuleViolation violation;
923 violation.errorCode = code;
924 violation.rules.insert(std::string(description));
926 dst.push_back(violation);
930 FboBuilder::FboBuilder (GLuint fbo, GLenum target, const glw::Functions& gl)
931 : m_error (GL_NO_ERROR)
935 m_gl.bindFramebuffer(m_target, fbo);
938 FboBuilder::~FboBuilder (void)
940 for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++)
942 glDelete(*it->second, it->first, m_gl);
944 for (RboMap::const_iterator it = rbos.begin(); it != rbos.end(); it++)
946 glDelete(*it->second, it->first, m_gl);
948 m_gl.bindFramebuffer(m_target, 0);
949 for (Configs::const_iterator it = m_configs.begin(); it != m_configs.end(); it++)
955 void FboBuilder::checkError (void)
957 const GLenum error = m_gl.getError();
958 if (error != GL_NO_ERROR && m_error == GL_NO_ERROR)
962 void FboBuilder::glAttach (GLenum attPoint, const Attachment* att)
965 m_gl.framebufferRenderbuffer(m_target, attPoint, GL_RENDERBUFFER, 0);
967 attachAttachment(*att, attPoint, m_gl);
969 attach(attPoint, att);
972 GLuint FboBuilder::glCreateTexture (const Texture& texCfg)
974 const GLuint texName = glCreate(texCfg, m_gl);
976 setTexture(texName, texCfg);
980 GLuint FboBuilder::glCreateRbo (const Renderbuffer& rbCfg)
982 const GLuint rbName = glCreate(rbCfg, m_gl);
984 setRbo(rbName, rbCfg);
988 TransferFormat transferImageFormat (const ImageFormat& imgFormat)
990 if (imgFormat.unsizedType == GL_NONE)
991 return getTransferFormat(mapGLInternalFormat(imgFormat.format));
993 return TransferFormat(imgFormat.format, imgFormat.unsizedType);