glsFboUtil.cpp revision b5c60b02e542a61a2b658272034c830f92b4c766
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 "deSTLUtil.hpp" 32#include <sstream> 33 34using namespace glw; 35using tcu::TestLog; 36using tcu::TextureFormat; 37using tcu::NotSupportedError; 38using glu::TransferFormat; 39using glu::mapGLInternalFormat; 40using glu::mapGLTransferFormat; 41using glu::getPixelFormatName; 42using glu::getTypeName; 43using glu::getFramebufferTargetName; 44using glu::getFramebufferAttachmentName; 45using glu::getFramebufferAttachmentTypeName; 46using glu::getTextureTargetName; 47using glu::getTransferFormat; 48using glu::ContextInfo; 49using glu::ContextType; 50using glu::RenderContext; 51using de::UniquePtr; 52using de::toString; 53using std::set; 54using std::vector; 55using std::string; 56using std::istringstream; 57using std::istream_iterator; 58 59namespace deqp 60{ 61namespace gls 62{ 63 64namespace FboUtil 65{ 66 67#if defined(DE_DEBUG) 68static bool isFramebufferStatus (glw::GLenum fboStatus) 69{ 70 return glu::getFramebufferStatusName(fboStatus) != DE_NULL; 71} 72 73static bool isErrorCode (glw::GLenum errorCode) 74{ 75 return glu::getErrorName(errorCode) != DE_NULL; 76} 77#endif 78 79std::ostream& operator<< (std::ostream& stream, const ImageFormat& format) 80{ 81 if (format.unsizedType == GL_NONE) 82 { 83 // sized format 84 return stream << glu::getPixelFormatStr(format.format); 85 } 86 else 87 { 88 // unsized format 89 return stream << "(format = " << glu::getPixelFormatStr(format.format) << ", type = " << glu::getTypeStr(format.unsizedType) << ")"; 90 } 91} 92 93void FormatDB::addCoreFormat (ImageFormat format, FormatFlags newFlags) 94{ 95 FormatFlags& flags = m_formatFlags[format]; 96 flags = FormatFlags(flags | newFlags); 97} 98 99void FormatDB::addExtensionFormat (ImageFormat format, FormatFlags newFlags, const std::set<std::string>& requiredExtensions) 100{ 101 DE_ASSERT(!requiredExtensions.empty()); 102 103 { 104 FormatFlags& flags = m_formatFlags[format]; 105 flags = FormatFlags(flags | newFlags); 106 } 107 108 { 109 std::set<ExtensionInfo>& extensionInfo = m_formatExtensions[format]; 110 ExtensionInfo extensionRecord; 111 112 extensionRecord.flags = newFlags; 113 extensionRecord.requiredExtensions = requiredExtensions; 114 115 DE_ASSERT(!de::contains(extensionInfo, extensionRecord)); // extensions specified only once 116 extensionInfo.insert(extensionRecord); 117 } 118} 119 120// Not too fast at the moment, might consider indexing? 121Formats FormatDB::getFormats (FormatFlags requirements) const 122{ 123 Formats ret; 124 for (FormatMap::const_iterator it = m_formatFlags.begin(); it != m_formatFlags.end(); it++) 125 { 126 if ((it->second & requirements) == requirements) 127 ret.insert(it->first); 128 } 129 return ret; 130} 131 132bool FormatDB::isKnownFormat (ImageFormat format) const 133{ 134 return de::contains(m_formatFlags, format); 135} 136 137FormatFlags FormatDB::getFormatInfo (ImageFormat format) const 138{ 139 DE_ASSERT(de::contains(m_formatFlags, format)); 140 return de::lookup(m_formatFlags, format); 141} 142 143std::set<std::set<std::string> > FormatDB::getFormatFeatureExtensions (ImageFormat format, FormatFlags requirements) const 144{ 145 DE_ASSERT(de::contains(m_formatExtensions, format)); 146 147 const std::set<ExtensionInfo>& extensionInfo = de::lookup(m_formatExtensions, format); 148 std::set<std::set<std::string> > ret; 149 150 for (std::set<ExtensionInfo>::const_iterator it = extensionInfo.begin(); it != extensionInfo.end(); ++it) 151 { 152 if ((it->flags & requirements) == requirements) 153 ret.insert(it->requiredExtensions); 154 } 155 156 return ret; 157} 158 159bool FormatDB::ExtensionInfo::operator< (const ExtensionInfo& other) const 160{ 161 return (requiredExtensions < other.requiredExtensions) || 162 ((requiredExtensions == other.requiredExtensions) && (flags < other.flags)); 163} 164 165void addFormats (FormatDB& db, FormatEntries stdFmts) 166{ 167 for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++) 168 { 169 for (const FormatKey* it2 = it->second.begin(); it2 != it->second.end(); it2++) 170 db.addCoreFormat(formatKeyInfo(*it2), it->first); 171 } 172} 173 174void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const RenderContext* ctx) 175{ 176 const UniquePtr<ContextInfo> ctxInfo(ctx != DE_NULL ? ContextInfo::create(*ctx) : DE_NULL); 177 for (const FormatExtEntry* entryIt = extFmts.begin(); entryIt != extFmts.end(); entryIt++) 178 { 179 bool supported = true; 180 std::set<std::string> requiredExtensions; 181 182 // parse required extensions 183 { 184 istringstream tokenStream(string(entryIt->extensions)); 185 istream_iterator<string> tokens((tokenStream)), end; 186 187 while (tokens != end) 188 { 189 requiredExtensions.insert(*tokens); 190 ++tokens; 191 } 192 } 193 194 // check support 195 if (ctxInfo) 196 { 197 for (std::set<std::string>::const_iterator extIt = requiredExtensions.begin(); extIt != requiredExtensions.end(); ++extIt) 198 { 199 if (!ctxInfo->isExtensionSupported(extIt->c_str())) 200 { 201 supported = false; 202 break; 203 } 204 } 205 } 206 207 if (supported) 208 for (const FormatKey* i2 = entryIt->formats.begin(); i2 != entryIt->formats.end(); i2++) 209 db.addExtensionFormat(formatKeyInfo(*i2), FormatFlags(entryIt->flags), requiredExtensions); 210 } 211} 212 213FormatFlags formatFlag (GLenum context) 214{ 215 switch (context) 216 { 217 case GL_NONE: 218 return FormatFlags(0); 219 case GL_RENDERBUFFER: 220 return RENDERBUFFER_VALID; 221 case GL_TEXTURE: 222 return TEXTURE_VALID; 223 case GL_STENCIL_ATTACHMENT: 224 return STENCIL_RENDERABLE; 225 case GL_DEPTH_ATTACHMENT: 226 return DEPTH_RENDERABLE; 227 default: 228 DE_ASSERT(context >= GL_COLOR_ATTACHMENT0 && context <= GL_COLOR_ATTACHMENT15); 229 return COLOR_RENDERABLE; 230 } 231} 232 233static FormatFlags getAttachmentRenderabilityFlag (GLenum attachment) 234{ 235 switch (attachment) 236 { 237 case GL_STENCIL_ATTACHMENT: return STENCIL_RENDERABLE; 238 case GL_DEPTH_ATTACHMENT: return DEPTH_RENDERABLE; 239 240 default: 241 DE_ASSERT(attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15); 242 return COLOR_RENDERABLE; 243 } 244} 245 246namespace config { 247 248GLsizei imageNumSamples (const Image& img) 249{ 250 if (const Renderbuffer* rbo = dynamic_cast<const Renderbuffer*>(&img)) 251 return rbo->numSamples; 252 return 0; 253} 254 255static GLenum glTarget (const Image& img) 256{ 257 if (dynamic_cast<const Renderbuffer*>(&img) != DE_NULL) 258 return GL_RENDERBUFFER; 259 if (dynamic_cast<const Texture2D*>(&img) != DE_NULL) 260 return GL_TEXTURE_2D; 261 if (dynamic_cast<const TextureCubeMap*>(&img) != DE_NULL) 262 return GL_TEXTURE_CUBE_MAP; 263 if (dynamic_cast<const Texture3D*>(&img) != DE_NULL) 264 return GL_TEXTURE_3D; 265 if (dynamic_cast<const Texture2DArray*>(&img) != DE_NULL) 266 return GL_TEXTURE_2D_ARRAY; 267 268 DE_ASSERT(!"Impossible image type"); 269 return GL_NONE; 270} 271 272static void glInitFlat (const TextureFlat& cfg, GLenum target, const glw::Functions& gl) 273{ 274 const TransferFormat format = transferImageFormat(cfg.internalFormat); 275 GLint w = cfg.width; 276 GLint h = cfg.height; 277 for (GLint level = 0; level < cfg.numLevels; level++) 278 { 279 gl.texImage2D(target, level, cfg.internalFormat.format, w, h, 0, 280 format.format, format.dataType, DE_NULL); 281 w = de::max(1, w / 2); 282 h = de::max(1, h / 2); 283 } 284} 285 286static void glInitLayered (const TextureLayered& cfg, 287 GLint depth_divider, const glw::Functions& gl) 288{ 289 const TransferFormat format = transferImageFormat(cfg.internalFormat); 290 GLint w = cfg.width; 291 GLint h = cfg.height; 292 GLint depth = cfg.numLayers; 293 for (GLint level = 0; level < cfg.numLevels; level++) 294 { 295 gl.texImage3D(glTarget(cfg), level, cfg.internalFormat.format, w, h, depth, 0, 296 format.format, format.dataType, DE_NULL); 297 w = de::max(1, w / 2); 298 h = de::max(1, h / 2); 299 depth = de::max(1, depth / depth_divider); 300 } 301} 302 303static void glInit (const Texture& cfg, const glw::Functions& gl) 304{ 305 if (const Texture2D* t2d = dynamic_cast<const Texture2D*>(&cfg)) 306 glInitFlat(*t2d, glTarget(*t2d), gl); 307 else if (const TextureCubeMap* tcm = dynamic_cast<const TextureCubeMap*>(&cfg)) 308 { 309 // \todo [2013-12-05 lauri] 310 // move this to glu or someplace sensible (this array is already 311 // present in duplicates) 312 static const GLenum s_cubeMapFaces[] = 313 { 314 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 315 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 316 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 317 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 318 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 319 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 320 }; 321 const Range<GLenum> range = GLS_ARRAY_RANGE(s_cubeMapFaces); 322 for (const GLenum* it = range.begin(); it != range.end(); it++) 323 glInitFlat(*tcm, *it, gl); 324 } 325 else if (const Texture3D* t3d = dynamic_cast<const Texture3D*>(&cfg)) 326 glInitLayered(*t3d, 2, gl); 327 else if (const Texture2DArray* t2a = dynamic_cast<const Texture2DArray*>(&cfg)) 328 glInitLayered(*t2a, 1, gl); 329} 330 331static GLuint glCreate (const Image& cfg, const glw::Functions& gl) 332{ 333 GLuint ret = 0; 334 if (const Renderbuffer* const rbo = dynamic_cast<const Renderbuffer*>(&cfg)) 335 { 336 gl.genRenderbuffers(1, &ret); 337 gl.bindRenderbuffer(GL_RENDERBUFFER, ret); 338 339 if (rbo->numSamples == 0) 340 gl.renderbufferStorage(GL_RENDERBUFFER, rbo->internalFormat.format, 341 rbo->width, rbo->height); 342 else 343 gl.renderbufferStorageMultisample( 344 GL_RENDERBUFFER, rbo->numSamples, rbo->internalFormat.format, 345 rbo->width, rbo->height); 346 347 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 348 } 349 else if (const Texture* const tex = dynamic_cast<const Texture*>(&cfg)) 350 { 351 gl.genTextures(1, &ret); 352 gl.bindTexture(glTarget(*tex), ret); 353 glInit(*tex, gl); 354 gl.bindTexture(glTarget(*tex), 0); 355 } 356 else 357 DE_ASSERT(!"Impossible image type"); 358 return ret; 359} 360 361static void glDelete (const Image& cfg, GLuint img, const glw::Functions& gl) 362{ 363 if (dynamic_cast<const Renderbuffer*>(&cfg) != DE_NULL) 364 gl.deleteRenderbuffers(1, &img); 365 else if (dynamic_cast<const Texture*>(&cfg) != DE_NULL) 366 gl.deleteTextures(1, &img); 367 else 368 DE_ASSERT(!"Impossible image type"); 369} 370 371static void attachAttachment (const Attachment& att, GLenum attPoint, 372 const glw::Functions& gl) 373{ 374 if (const RenderbufferAttachment* const rAtt = 375 dynamic_cast<const RenderbufferAttachment*>(&att)) 376 gl.framebufferRenderbuffer(rAtt->target, attPoint, 377 rAtt->renderbufferTarget, rAtt->imageName); 378 else if (const TextureFlatAttachment* const fAtt = 379 dynamic_cast<const TextureFlatAttachment*>(&att)) 380 gl.framebufferTexture2D(fAtt->target, attPoint, 381 fAtt->texTarget, fAtt->imageName, fAtt->level); 382 else if (const TextureLayerAttachment* const lAtt = 383 dynamic_cast<const TextureLayerAttachment*>(&att)) 384 gl.framebufferTextureLayer(lAtt->target, attPoint, 385 lAtt->imageName, lAtt->level, lAtt->layer); 386 else 387 DE_ASSERT(!"Impossible attachment type"); 388} 389 390GLenum attachmentType (const Attachment& att) 391{ 392 if (dynamic_cast<const RenderbufferAttachment*>(&att) != DE_NULL) 393 return GL_RENDERBUFFER; 394 else if (dynamic_cast<const TextureAttachment*>(&att) != DE_NULL) 395 return GL_TEXTURE; 396 397 DE_ASSERT(!"Impossible attachment type"); 398 return GL_NONE; 399} 400 401static GLsizei textureLayer (const TextureAttachment& tAtt) 402{ 403 if (dynamic_cast<const TextureFlatAttachment*>(&tAtt) != DE_NULL) 404 return 0; 405 else if (const TextureLayerAttachment* const lAtt = 406 dynamic_cast<const TextureLayerAttachment*>(&tAtt)) 407 return lAtt->layer; 408 409 DE_ASSERT(!"Impossible attachment type"); 410 return 0; 411} 412 413static void checkAttachmentCompleteness (Checker& cctx, const Attachment& attachment, 414 GLenum attPoint, const Image* image, 415 const FormatDB& db) 416{ 417 // GLES2 4.4.5 / GLES3 4.4.4, "Framebuffer attachment completeness" 418 419 if (const TextureAttachment* const texAtt = 420 dynamic_cast<const TextureAttachment*>(&attachment)) 421 if (const TextureLayered* const ltex = dynamic_cast<const TextureLayered*>(image)) 422 { 423 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is 424 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a 425 // three-dimensional texture, then the value of 426 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth 427 // of the texture. 428 // 429 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is 430 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a 431 // two-dimensional array texture, then the value of 432 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the 433 // number of layers in the texture. 434 435 if (textureLayer(*texAtt) >= ltex->numLayers) 436 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attached layer index is larger than present"); 437 } 438 439 // "The width and height of image are non-zero." 440 if (image->width == 0 || image->height == 0) 441 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Width and height of an image are not non-zero"); 442 443 // Check for renderability 444 if (db.isKnownFormat(image->internalFormat)) 445 { 446 const FormatFlags flags = db.getFormatInfo(image->internalFormat); 447 448 // If the format does not have the proper renderability flag, the 449 // completeness check _must_ fail. 450 if ((flags & getAttachmentRenderabilityFlag(attPoint)) == 0) 451 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not renderable in this attachment"); 452 // If the format is only optionally renderable, the completeness check _can_ fail. 453 else if ((flags & REQUIRED_RENDERABLE) == 0) 454 cctx.addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not required renderable"); 455 } 456 else 457 cctx.addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, "Attachment format is not legal"); 458} 459 460} // namespace config 461 462using namespace config; 463 464Checker::Checker (void) 465{ 466 m_statusCodes.setAllowComplete(true); 467} 468 469void Checker::addGLError (glw::GLenum error, const char* description) 470{ 471 m_statusCodes.addErrorCode(error, description); 472 m_statusCodes.setAllowComplete(false); 473} 474 475void Checker::addPotentialGLError (glw::GLenum error, const char* description) 476{ 477 m_statusCodes.addErrorCode(error, description); 478} 479 480void Checker::addFBOStatus (GLenum status, const char* description) 481{ 482 m_statusCodes.addFBOErrorStatus(status, description); 483 m_statusCodes.setAllowComplete(false); 484} 485 486void Checker::addPotentialFBOStatus (GLenum status, const char* description) 487{ 488 m_statusCodes.addFBOErrorStatus(status, description); 489} 490 491FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory) 492 : m_formats (formats) 493 , m_factory (factory) 494{ 495} 496 497/*--------------------------------------------------------------------*//*! 498 * \brief Return acceptable framebuffer status codes. 499 * 500 * This function examines the framebuffer configuration descriptor `fboConfig` 501 * and returns the set of status codes that `glCheckFramebufferStatus` is 502 * allowed to return on a conforming implementation when given a framebuffer 503 * whose configuration adheres to `fboConfig`. 504 * 505 * The returned set is guaranteed to be non-empty, but it may contain multiple 506 * INCOMPLETE statuses (if there are multiple errors in the spec), or or a mix 507 * of COMPLETE and INCOMPLETE statuses (if supporting a FBO with this spec is 508 * optional). Furthermore, the statuses may contain GL error codes, which 509 * indicate that trying to create a framebuffer configuration like this could 510 * have failed with an error (if one was checked for) even before 511 * `glCheckFramebufferStatus` was ever called. 512 * 513 *//*--------------------------------------------------------------------*/ 514ValidStatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const 515{ 516 const AttachmentMap& atts = fboConfig.attachments; 517 const UniquePtr<Checker> cctx(m_factory.createChecker()); 518 519 for (TextureMap::const_iterator it = fboConfig.textures.begin(); 520 it != fboConfig.textures.end(); it++) 521 { 522 std::string errorDescription; 523 524 if (m_formats.isKnownFormat(it->second->internalFormat)) 525 { 526 const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat); 527 528 if ((flags & TEXTURE_VALID) == 0) 529 errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a texture"; 530 } 531 else if (it->second->internalFormat.unsizedType == GL_NONE) 532 { 533 // sized format 534 errorDescription = "Format " + de::toString(it->second->internalFormat) + " does not exist"; 535 } 536 else 537 { 538 // unsized type-format pair 539 errorDescription = "Format " + de::toString(it->second->internalFormat) + " is not a legal format"; 540 } 541 542 if (!errorDescription.empty()) 543 { 544 cctx->addGLError(GL_INVALID_ENUM, errorDescription.c_str()); 545 cctx->addGLError(GL_INVALID_OPERATION, errorDescription.c_str()); 546 cctx->addGLError(GL_INVALID_VALUE, errorDescription.c_str()); 547 } 548 } 549 550 for (RboMap::const_iterator it = fboConfig.rbos.begin(); it != fboConfig.rbos.end(); it++) 551 { 552 if (m_formats.isKnownFormat(it->second->internalFormat)) 553 { 554 const FormatFlags flags = m_formats.getFormatInfo(it->second->internalFormat); 555 if ((flags & RENDERBUFFER_VALID) == 0) 556 { 557 const std::string reason = "Format " + de::toString(it->second->internalFormat) + " is not a valid format for a renderbuffer"; 558 cctx->addGLError(GL_INVALID_ENUM, reason.c_str()); 559 } 560 } 561 else 562 { 563 const std::string reason = "Internal format " + de::toString(it->second->internalFormat) + " does not exist"; 564 cctx->addGLError(GL_INVALID_ENUM, reason.c_str()); 565 } 566 } 567 568 // "There is at least one image attached to the framebuffer." 569 // \todo support XXX_framebuffer_no_attachments 570 if (atts.empty()) 571 cctx->addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, "No images attached to the framebuffer"); 572 573 for (AttachmentMap::const_iterator it = atts.begin(); it != atts.end(); it++) 574 { 575 const GLenum attPoint = it->first; 576 const Attachment& att = *it->second; 577 const Image* const image = fboConfig.getImage(attachmentType(att), att.imageName); 578 579 checkAttachmentCompleteness(*cctx, att, attPoint, image, m_formats); 580 cctx->check(it->first, *it->second, image); 581 } 582 583 return cctx->getStatusCodes(); 584} 585 586 587void Framebuffer::attach (glw::GLenum attPoint, const Attachment* att) 588{ 589 if (att == DE_NULL) 590 attachments.erase(attPoint); 591 else 592 attachments[attPoint] = att; 593} 594 595const Image* Framebuffer::getImage (GLenum type, glw::GLuint imgName) const 596{ 597 switch (type) 598 { 599 case GL_TEXTURE: 600 return de::lookupDefault(textures, imgName, DE_NULL); 601 case GL_RENDERBUFFER: 602 return de::lookupDefault(rbos, imgName, DE_NULL); 603 default: 604 DE_ASSERT(!"Bad image type"); 605 } 606 return DE_NULL; // shut up compiler warning 607} 608 609void Framebuffer::setTexture (glw::GLuint texName, const Texture& texCfg) 610{ 611 textures[texName] = &texCfg; 612} 613 614void Framebuffer::setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg) 615{ 616 rbos[rbName] = &rbCfg; 617} 618 619static void logField (TestLog& log, const string& field, const string& value) 620{ 621 log << TestLog::Message << field << ": " << value << TestLog::EndMessage; 622} 623 624static void logImage (const Image& img, TestLog& log, bool useType) 625{ 626 const GLenum type = img.internalFormat.unsizedType; 627 logField(log, "Internal format", getPixelFormatName(img.internalFormat.format)); 628 if (useType && type != GL_NONE) 629 logField(log, "Format type", getTypeName(type)); 630 logField(log, "Width", toString(img.width)); 631 logField(log, "Height", toString(img.height)); 632} 633 634static void logRenderbuffer (const Renderbuffer& rbo, TestLog& log) 635{ 636 logImage(rbo, log, false); 637 logField(log, "Samples", toString(rbo.numSamples)); 638} 639 640static void logTexture (const Texture& tex, TestLog& log) 641{ 642 logField(log, "Type", glu::getTextureTargetName(glTarget(tex))); 643 logImage(tex, log, true); 644 logField(log, "Levels", toString(tex.numLevels)); 645 if (const TextureLayered* const lTex = dynamic_cast<const TextureLayered*>(&tex)) 646 logField(log, "Layers", toString(lTex->numLayers)); 647} 648 649static void logAttachment (const Attachment& att, TestLog& log) 650{ 651 logField(log, "Target", getFramebufferTargetName(att.target)); 652 logField(log, "Type", getFramebufferAttachmentTypeName(attachmentType(att))); 653 logField(log, "Image Name", toString(att.imageName)); 654 if (const RenderbufferAttachment* const rAtt 655 = dynamic_cast<const RenderbufferAttachment*>(&att)) 656 { 657 DE_UNREF(rAtt); // To shut up compiler during optimized builds. 658 DE_ASSERT(rAtt->renderbufferTarget == GL_RENDERBUFFER); 659 logField(log, "Renderbuffer Target", "GL_RENDERBUFFER"); 660 } 661 else if (const TextureAttachment* const tAtt = dynamic_cast<const TextureAttachment*>(&att)) 662 { 663 logField(log, "Mipmap Level", toString(tAtt->level)); 664 if (const TextureFlatAttachment* const fAtt = 665 dynamic_cast<const TextureFlatAttachment*>(tAtt)) 666 logField(log, "Texture Target", getTextureTargetName(fAtt->texTarget)); 667 else if (const TextureLayerAttachment* const lAtt = 668 dynamic_cast<const TextureLayerAttachment*>(tAtt)) 669 logField(log, "Layer", toString(lAtt->level)); 670 } 671} 672 673void logFramebufferConfig (const Framebuffer& cfg, TestLog& log) 674{ 675 log << TestLog::Section("Framebuffer", "Framebuffer configuration"); 676 677 for (RboMap::const_iterator it = cfg.rbos.begin(); it != cfg.rbos.end(); ++it) 678 { 679 const string num = toString(it->first); 680 const tcu::ScopedLogSection subsection (log, num, "Renderbuffer " + num); 681 682 logRenderbuffer(*it->second, log); 683 } 684 685 for (TextureMap::const_iterator it = cfg.textures.begin(); 686 it != cfg.textures.end(); ++it) 687 { 688 const string num = toString(it->first); 689 const tcu::ScopedLogSection subsection (log, num, "Texture " + num); 690 691 logTexture(*it->second, log); 692 } 693 694 const string attDesc = cfg.attachments.empty() 695 ? "Framebuffer has no attachments" 696 : "Framebuffer attachments"; 697 log << TestLog::Section("Attachments", attDesc); 698 for (AttachmentMap::const_iterator it = cfg.attachments.begin(); 699 it != cfg.attachments.end(); it++) 700 { 701 const string attPointName = getFramebufferAttachmentName(it->first); 702 log << TestLog::Section(attPointName, "Attachment point " + attPointName); 703 logAttachment(*it->second, log); 704 log << TestLog::EndSection; 705 } 706 log << TestLog::EndSection; // Attachments 707 708 log << TestLog::EndSection; // Framebuffer 709} 710 711ValidStatusCodes::ValidStatusCodes (void) 712 : m_allowComplete(false) 713{ 714} 715 716bool ValidStatusCodes::isFBOStatusValid (glw::GLenum fboStatus) const 717{ 718 if (fboStatus == GL_FRAMEBUFFER_COMPLETE) 719 return m_allowComplete; 720 else 721 { 722 // rule violation exists? 723 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx) 724 { 725 if (m_errorStatuses[ndx].errorCode == fboStatus) 726 return true; 727 } 728 return false; 729 } 730} 731 732bool ValidStatusCodes::isFBOStatusRequired (glw::GLenum fboStatus) const 733{ 734 if (fboStatus == GL_FRAMEBUFFER_COMPLETE) 735 return m_allowComplete && m_errorStatuses.empty(); 736 else 737 // fboStatus is the only allowed error status and succeeding is forbidden 738 return !m_allowComplete && m_errorStatuses.size() == 1 && m_errorStatuses.front().errorCode == fboStatus; 739} 740 741bool ValidStatusCodes::isErrorCodeValid (glw::GLenum errorCode) const 742{ 743 if (errorCode == GL_NO_ERROR) 744 return m_errorCodes.empty(); 745 else 746 { 747 // rule violation exists? 748 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx) 749 { 750 if (m_errorCodes[ndx].errorCode == errorCode) 751 return true; 752 } 753 return false; 754 } 755} 756 757bool ValidStatusCodes::isErrorCodeRequired (glw::GLenum errorCode) const 758{ 759 if (m_errorCodes.empty() && errorCode == GL_NO_ERROR) 760 return true; 761 else 762 // only this error code listed 763 return m_errorCodes.size() == 1 && m_errorCodes.front().errorCode == errorCode; 764} 765 766void ValidStatusCodes::addErrorCode (glw::GLenum error, const char* description) 767{ 768 DE_ASSERT(isErrorCode(error)); 769 DE_ASSERT(error != GL_NO_ERROR); 770 addViolation(m_errorCodes, error, description); 771} 772 773void ValidStatusCodes::addFBOErrorStatus (glw::GLenum status, const char* description) 774{ 775 DE_ASSERT(isFramebufferStatus(status)); 776 DE_ASSERT(status != GL_FRAMEBUFFER_COMPLETE); 777 addViolation(m_errorStatuses, status, description); 778} 779 780void ValidStatusCodes::setAllowComplete (bool b) 781{ 782 m_allowComplete = b; 783} 784 785void ValidStatusCodes::logLegalResults (tcu::TestLog& log) const 786{ 787 tcu::MessageBuilder msg (&log); 788 std::vector<std::string> validResults; 789 790 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx) 791 validResults.push_back(std::string(glu::getErrorName(m_errorCodes[ndx].errorCode)) + " (during FBO initialization)"); 792 793 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx) 794 validResults.push_back(glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode)); 795 796 if (m_allowComplete) 797 validResults.push_back("GL_FRAMEBUFFER_COMPLETE"); 798 799 msg << "Expected "; 800 if (validResults.size() > 1) 801 msg << "one of "; 802 803 for (int ndx = 0; ndx < (int)validResults.size(); ++ndx) 804 { 805 const bool last = ((ndx + 1) == (int)validResults.size()); 806 const bool secondToLast = ((ndx + 2) == (int)validResults.size()); 807 808 msg << validResults[ndx]; 809 if (!last) 810 msg << ((secondToLast) ? (" or ") : (", ")); 811 } 812 813 msg << "." << TestLog::EndMessage; 814} 815 816void ValidStatusCodes::logRules (tcu::TestLog& log) const 817{ 818 const tcu::ScopedLogSection section(log, "Rules", "Active rules"); 819 820 for (int ndx = 0; ndx < (int)m_errorCodes.size(); ++ndx) 821 logRule(log, glu::getErrorName(m_errorCodes[ndx].errorCode), m_errorCodes[ndx].rules); 822 823 for (int ndx = 0; ndx < (int)m_errorStatuses.size(); ++ndx) 824 logRule(log, glu::getFramebufferStatusName(m_errorStatuses[ndx].errorCode), m_errorStatuses[ndx].rules); 825 826 if (m_allowComplete) 827 { 828 std::set<std::string> defaultRule; 829 defaultRule.insert("FBO is complete"); 830 logRule(log, "GL_FRAMEBUFFER_COMPLETE", defaultRule); 831 } 832} 833 834void ValidStatusCodes::logRule (tcu::TestLog& log, const std::string& ruleName, const std::set<std::string>& rules) const 835{ 836 if (!rules.empty()) 837 { 838 const tcu::ScopedLogSection section (log, ruleName, ruleName); 839 tcu::MessageBuilder msg (&log); 840 841 msg << "Rules:\n"; 842 for (std::set<std::string>::const_iterator it = rules.begin(); it != rules.end(); ++it) 843 msg << "\t * " << *it << "\n"; 844 msg << TestLog::EndMessage; 845 } 846} 847 848void ValidStatusCodes::addViolation (std::vector<RuleViolation>& dst, glw::GLenum code, const char* description) const 849{ 850 // rule violation already exists? 851 for (int ndx = 0; ndx < (int)dst.size(); ++ndx) 852 { 853 if (dst[ndx].errorCode == code) 854 { 855 dst[ndx].rules.insert(std::string(description)); 856 return; 857 } 858 } 859 860 // new violation 861 { 862 RuleViolation violation; 863 864 violation.errorCode = code; 865 violation.rules.insert(std::string(description)); 866 867 dst.push_back(violation); 868 } 869} 870 871FboBuilder::FboBuilder (GLuint fbo, GLenum target, const glw::Functions& gl) 872 : m_error (GL_NO_ERROR) 873 , m_target (target) 874 , m_gl (gl) 875{ 876 m_gl.bindFramebuffer(m_target, fbo); 877} 878 879FboBuilder::~FboBuilder (void) 880{ 881 for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++) 882 { 883 glDelete(*it->second, it->first, m_gl); 884 } 885 for (RboMap::const_iterator it = rbos.begin(); it != rbos.end(); it++) 886 { 887 glDelete(*it->second, it->first, m_gl); 888 } 889 m_gl.bindFramebuffer(m_target, 0); 890 for (Configs::const_iterator it = m_configs.begin(); it != m_configs.end(); it++) 891 { 892 delete *it; 893 } 894} 895 896void FboBuilder::checkError (void) 897{ 898 const GLenum error = m_gl.getError(); 899 if (error != GL_NO_ERROR && m_error == GL_NO_ERROR) 900 m_error = error; 901} 902 903void FboBuilder::glAttach (GLenum attPoint, const Attachment* att) 904{ 905 if (att == NULL) 906 m_gl.framebufferRenderbuffer(m_target, attPoint, GL_RENDERBUFFER, 0); 907 else 908 attachAttachment(*att, attPoint, m_gl); 909 checkError(); 910 attach(attPoint, att); 911} 912 913GLuint FboBuilder::glCreateTexture (const Texture& texCfg) 914{ 915 const GLuint texName = glCreate(texCfg, m_gl); 916 checkError(); 917 setTexture(texName, texCfg); 918 return texName; 919} 920 921GLuint FboBuilder::glCreateRbo (const Renderbuffer& rbCfg) 922{ 923 const GLuint rbName = glCreate(rbCfg, m_gl); 924 checkError(); 925 setRbo(rbName, rbCfg); 926 return rbName; 927} 928 929TransferFormat transferImageFormat (const ImageFormat& imgFormat) 930{ 931 if (imgFormat.unsizedType == GL_NONE) 932 return getTransferFormat(mapGLInternalFormat(imgFormat.format)); 933 else 934 return TransferFormat(imgFormat.format, imgFormat.unsizedType); 935} 936 937} // FboUtil 938} // gls 939} // deqp 940