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 Framebuffer completeness tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fFboCompletenessTests.hpp" 25 26 #include "glsFboCompletenessTests.hpp" 27 #include <sstream> 28 29 using namespace glw; 30 using deqp::gls::Range; 31 using namespace deqp::gls::FboUtil; 32 using namespace deqp::gls::FboUtil::config; 33 namespace fboc = deqp::gls::fboc; 34 typedef tcu::TestCase::IterateResult IterateResult; 35 using std::string; 36 using std::ostringstream; 37 38 namespace deqp 39 { 40 namespace gles3 41 { 42 namespace Functional 43 { 44 45 static const FormatKey s_es3ColorRenderables[] = 46 { 47 // GLES3, 4.4.4: "An internal format is color-renderable if it is one of 48 // the formats from table 3.12 noted as color-renderable..." 49 GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, 50 GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8_ALPHA8, 51 GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI, 52 GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, 53 GL_RGBA8I, GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI, 54 }; 55 56 static const FormatKey s_es3UnsizedColorRenderables[] = 57 { 58 // "...or if it is unsized format RGBA or RGB." 59 // See Table 3.3 in GLES3. 60 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_BYTE), 61 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4), 62 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1), 63 GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_BYTE), 64 GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_SHORT_5_6_5), 65 }; 66 67 static const FormatKey s_es3DepthRenderables[] = 68 { 69 // GLES3, 4.4.4: "An internal format is depth-renderable if it is one of 70 // the formats from table 3.13." 71 GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F, 72 GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, 73 }; 74 75 static const FormatKey s_es3StencilRboRenderables[] = 76 { 77 // GLES3, 4.4.4: "An internal format is stencil-renderable if it is 78 // STENCIL_INDEX8..." 79 GL_STENCIL_INDEX8, 80 }; 81 82 static const FormatKey s_es3StencilRenderables[] = 83 { 84 // "...or one of the formats from table 3.13 whose base internal format is 85 // DEPTH_STENCIL." 86 GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, 87 }; 88 89 static const FormatKey s_es3TextureFloatFormats[] = 90 { 91 GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, 92 GL_RG32F, GL_RG16F, GL_R32F, GL_R16F, 93 GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F, 94 }; 95 96 static const FormatKey s_es3NotRenderableTextureFormats[] = 97 { 98 GL_R8_SNORM, GL_RG8_SNORM, GL_RGB8_SNORM, GL_RGBA8_SNORM, 99 GL_RGB9_E5, GL_SRGB8, 100 GL_RGB8I, GL_RGB16I, GL_RGB32I, 101 GL_RGB8UI, GL_RGB16UI,GL_RGB32UI, 102 }; 103 104 static const FormatEntry s_es3Formats[] = 105 { 106 // Renderbuffers don't support unsized formats 107 { REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID, 108 GLS_ARRAY_RANGE(s_es3UnsizedColorRenderables) }, 109 { REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID, 110 GLS_ARRAY_RANGE(s_es3ColorRenderables) }, 111 { REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID, 112 GLS_ARRAY_RANGE(s_es3DepthRenderables) }, 113 { REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID, 114 GLS_ARRAY_RANGE(s_es3StencilRboRenderables) }, 115 { REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID, 116 GLS_ARRAY_RANGE(s_es3StencilRenderables) }, 117 { TEXTURE_VALID, 118 GLS_ARRAY_RANGE(s_es3NotRenderableTextureFormats) }, 119 120 // These are not color-renderable in vanilla ES3, but we need to mark them 121 // as valid for textures, since EXT_color_buffer_(half_)float brings in 122 // color-renderability and only renderbuffer-validity. 123 { TEXTURE_VALID, 124 GLS_ARRAY_RANGE(s_es3TextureFloatFormats) }, 125 }; 126 127 // GL_EXT_color_buffer_float 128 static const FormatKey s_extColorBufferFloatFormats[] = 129 { 130 GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F, 131 }; 132 133 // GL_OES_texture_stencil8 134 static const FormatKey s_extOESTextureStencil8[] = 135 { 136 GL_STENCIL_INDEX8, 137 }; 138 139 // GL_EXT_render_snorm 140 static const FormatKey s_extRenderSnorm[] = 141 { 142 GL_R8_SNORM, GL_RG8_SNORM, GL_RGBA8_SNORM, 143 }; 144 145 static const FormatExtEntry s_es3ExtFormats[] = 146 { 147 { 148 "GL_EXT_color_buffer_float", 149 // These are already texture-valid in ES3, the extension just adds RBO 150 // support and makes them color-renderable. 151 (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID), 152 GLS_ARRAY_RANGE(s_extColorBufferFloatFormats) 153 }, 154 { 155 "GL_OES_texture_stencil8", 156 // \note: es3 RBO tests actually cover the first two requirements 157 // - kept here for completeness 158 (deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID), 159 GLS_ARRAY_RANGE(s_extOESTextureStencil8) 160 }, 161 162 // Since GLES31 is backwards compatible to GLES3, we might actually be running on a GLES31. 163 // Add rule changes of GLES31 that have no corresponding GLES3 extension. 164 // 165 // \note Not all feature changes are listed here but only those that alter GLES3 subset of 166 // the formats 167 { 168 "DEQP_gles31_core_compatible GL_EXT_render_snorm", 169 (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID | RENDERBUFFER_VALID), 170 GLS_ARRAY_RANGE(s_extRenderSnorm) 171 }, 172 }; 173 174 class ES3Checker : public Checker 175 { 176 public: 177 ES3Checker (const glu::RenderContext& ctx) 178 : Checker (ctx) 179 , m_numSamples (-1) 180 , m_depthStencilImage (0) 181 , m_depthStencilType (GL_NONE) {} 182 void check (GLenum attPoint, const Attachment& att, const Image* image); 183 184 private: 185 //! The common number of samples of images. 186 GLsizei m_numSamples; 187 188 //! The common image for depth and stencil attachments. 189 GLuint m_depthStencilImage; 190 GLenum m_depthStencilType; 191 }; 192 193 void ES3Checker::check (GLenum attPoint, const Attachment& att, const Image* image) 194 { 195 GLsizei imgSamples = imageNumSamples(*image); 196 197 if (m_numSamples == -1) 198 { 199 m_numSamples = imgSamples; 200 } 201 else 202 { 203 // GLES3: "The value of RENDERBUFFER_SAMPLES is the same for all attached 204 // renderbuffers and, if the attached images are a mix of renderbuffers 205 // and textures, the value of RENDERBUFFER_SAMPLES is zero." 206 // 207 // On creating a renderbuffer: "If _samples_ is zero, then 208 // RENDERBUFFER_SAMPLES is set to zero. Otherwise [...] the resulting 209 // value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or 210 // equal to _samples_ and no more than the next larger sample count 211 // supported by the implementation." 212 213 // Either all attachments are zero-sample renderbuffers and/or 214 // textures, or none of them are. 215 if ((m_numSamples == 0) != (imgSamples == 0)) 216 addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Mixed multi- and single-sampled attachments"); 217 218 // If the attachments requested a different number of samples, the 219 // implementation is allowed to report this as incomplete. However, it 220 // is also possible that despite the different requests, the 221 // implementation allocated the same number of samples to both. Hence 222 // reporting the framebuffer as complete is also legal. 223 if (m_numSamples != imgSamples) 224 addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Number of samples differ"); 225 } 226 227 // "Depth and stencil attachments, if present, are the same image." 228 if (attPoint == GL_DEPTH_ATTACHMENT || attPoint == GL_STENCIL_ATTACHMENT) 229 { 230 if (m_depthStencilImage == 0) 231 { 232 m_depthStencilImage = att.imageName; 233 m_depthStencilType = attachmentType(att); 234 } 235 else 236 { 237 if (m_depthStencilImage != att.imageName || m_depthStencilType != attachmentType(att)) 238 addFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Depth and stencil attachments are not the same image"); 239 } 240 } 241 } 242 243 struct NumLayersParams 244 { 245 GLenum textureKind; //< GL_TEXTURE_3D or GL_TEXTURE_2D_ARRAY 246 GLsizei numLayers; //< Number of layers in texture 247 GLsizei attachmentLayer; //< Layer referenced by attachment 248 249 static string getName (const NumLayersParams& params); 250 static string getDescription (const NumLayersParams& params); 251 }; 252 253 string NumLayersParams::getName (const NumLayersParams& params) 254 { 255 ostringstream os; 256 const string kindStr = params.textureKind == GL_TEXTURE_3D ? "3d" : "2darr"; 257 os << kindStr << "_" << params.numLayers << "_" << params.attachmentLayer; 258 return os.str(); 259 } 260 261 string NumLayersParams::getDescription (const NumLayersParams& params) 262 { 263 ostringstream os; 264 const string kindStr = (params.textureKind == GL_TEXTURE_3D 265 ? "3D Texture" 266 : "2D Array Texture"); 267 os << kindStr + ", " 268 << params.numLayers << " layers, " 269 << "attached layer " << params.attachmentLayer << "."; 270 return os.str(); 271 } 272 273 class NumLayersTest : public fboc::ParamTest<NumLayersParams> 274 { 275 public: 276 NumLayersTest (fboc::Context& ctx, NumLayersParams param) 277 : fboc::ParamTest<NumLayersParams> (ctx, param) {} 278 279 IterateResult build (FboBuilder& builder); 280 }; 281 282 IterateResult NumLayersTest::build (FboBuilder& builder) 283 { 284 TextureLayered* texCfg = DE_NULL; 285 const GLenum target = GL_COLOR_ATTACHMENT0; 286 287 switch (m_params.textureKind) 288 { 289 case GL_TEXTURE_3D: 290 texCfg = &builder.makeConfig<Texture3D>(); 291 break; 292 case GL_TEXTURE_2D_ARRAY: 293 texCfg = &builder.makeConfig<Texture2DArray>(); 294 break; 295 default: 296 DE_FATAL("Impossible case"); 297 } 298 texCfg->internalFormat = getDefaultFormat(target, GL_TEXTURE); 299 texCfg->width = 64; 300 texCfg->height = 64; 301 texCfg->numLayers = m_params.numLayers; 302 const GLuint tex = builder.glCreateTexture(*texCfg); 303 304 TextureLayerAttachment* att = &builder.makeConfig<TextureLayerAttachment>(); 305 att->layer = m_params.attachmentLayer; 306 att->imageName = tex; 307 308 builder.glAttach(target, att); 309 310 return STOP; 311 } 312 313 enum 314 { 315 SAMPLES_NONE = -2, 316 SAMPLES_TEXTURE = -1 317 }; 318 struct NumSamplesParams 319 { 320 // >= 0: renderbuffer with N samples, -1: texture, -2: no attachment 321 GLsizei numSamples[3]; 322 323 static string getName (const NumSamplesParams& params); 324 static string getDescription (const NumSamplesParams& params); 325 }; 326 327 string NumSamplesParams::getName (const NumSamplesParams& params) 328 { 329 ostringstream os; 330 bool first = true; 331 for (const GLsizei* ns = DE_ARRAY_BEGIN(params.numSamples); 332 ns != DE_ARRAY_END(params.numSamples); 333 ns++) 334 { 335 if (first) 336 first = false; 337 else 338 os << "_"; 339 340 if (*ns == SAMPLES_NONE) 341 os << "none"; 342 else if (*ns == SAMPLES_TEXTURE) 343 os << "tex"; 344 else 345 os << "rbo" << *ns; 346 } 347 return os.str(); 348 } 349 350 string NumSamplesParams::getDescription (const NumSamplesParams& params) 351 { 352 ostringstream os; 353 bool first = true; 354 static const char* const s_names[] = { "color", "depth", "stencil" }; 355 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == DE_LENGTH_OF_ARRAY(params.numSamples)); 356 357 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_names); i++) 358 { 359 GLsizei ns = params.numSamples[i]; 360 361 if (ns == SAMPLES_NONE) 362 continue; 363 364 if (first) 365 first = false; 366 else 367 os << ", "; 368 369 if (ns == SAMPLES_TEXTURE) 370 os << "texture " << s_names[i] << " attachment"; 371 else 372 os << ns << "-sample renderbuffer " << s_names[i] << " attachment"; 373 } 374 return os.str(); 375 } 376 377 class NumSamplesTest : public fboc::ParamTest<NumSamplesParams> 378 { 379 public: 380 NumSamplesTest (fboc::Context& ctx, NumSamplesParams param) 381 : fboc::ParamTest<NumSamplesParams> (ctx, param) {} 382 383 IterateResult build (FboBuilder& builder); 384 }; 385 386 IterateResult NumSamplesTest::build (FboBuilder& builder) 387 { 388 static const GLenum s_targets[] = 389 { 390 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_DEPTH_ATTACHMENT, 391 }; 392 // Non-integer formats for each attachment type. 393 // \todo [2013-12-17 lauri] Add fixed/floating/integer metadata for formats so 394 // we can pick one smartly or maybe try several. 395 static const GLenum s_formats[] = 396 { 397 GL_RGBA8, GL_RGB565, GL_DEPTH_COMPONENT24, 398 }; 399 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_targets) == DE_LENGTH_OF_ARRAY(m_params.numSamples)); 400 401 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_targets); i++) 402 { 403 const GLenum target = s_targets[i]; 404 const ImageFormat fmt = { s_formats[i], GL_NONE }; 405 406 const GLsizei ns = m_params.numSamples[i]; 407 if (ns == -2) 408 continue; 409 410 if (ns == -1) 411 { 412 attachTargetToNew(target, GL_TEXTURE, fmt, 64, 64, builder); 413 } 414 else 415 { 416 Renderbuffer& rboCfg = builder.makeConfig<Renderbuffer>(); 417 rboCfg.internalFormat = fmt; 418 rboCfg.width = rboCfg.height = 64; 419 rboCfg.numSamples = ns; 420 421 const GLuint rbo = builder.glCreateRbo(rboCfg); 422 // Implementations do not necessarily support sample sizes greater than 1. 423 TCU_CHECK_AND_THROW(NotSupportedError, 424 builder.getError() != GL_INVALID_OPERATION, 425 "Unsupported number of samples"); 426 RenderbufferAttachment& att = builder.makeConfig<RenderbufferAttachment>(); 427 att.imageName = rbo; 428 builder.glAttach(target, &att); 429 } 430 } 431 432 return STOP; 433 } 434 435 class ES3CheckerFactory : public CheckerFactory 436 { 437 public: 438 Checker* createChecker (const glu::RenderContext& ctx) { return new ES3Checker(ctx); } 439 }; 440 441 class TestGroup : public TestCaseGroup 442 { 443 public: 444 TestGroup (Context& context); 445 void init (void); 446 private: 447 ES3CheckerFactory m_checkerFactory; 448 fboc::Context m_fboc; 449 }; 450 451 void TestGroup::init (void) 452 { 453 addChild(m_fboc.createRenderableTests()); 454 addChild(m_fboc.createAttachmentTests()); 455 addChild(m_fboc.createSizeTests()); 456 457 TestCaseGroup* layerTests = new TestCaseGroup( 458 getContext(), "layer", "Tests for layer attachments"); 459 460 static const NumLayersParams s_layersParams[] = 461 { // textureKind numLayers attachmentKind 462 { GL_TEXTURE_2D_ARRAY, 1, 0 }, 463 { GL_TEXTURE_2D_ARRAY, 1, 3 }, 464 { GL_TEXTURE_2D_ARRAY, 4, 3 }, 465 { GL_TEXTURE_2D_ARRAY, 4, 15 }, 466 { GL_TEXTURE_3D, 1, 0 }, 467 { GL_TEXTURE_3D, 1, 15 }, 468 { GL_TEXTURE_3D, 4, 15 }, 469 { GL_TEXTURE_3D, 64, 15 }, 470 }; 471 472 for (const NumLayersParams* lp = DE_ARRAY_BEGIN(s_layersParams); 473 lp != DE_ARRAY_END(s_layersParams); 474 ++lp) 475 layerTests->addChild(new NumLayersTest(m_fboc, *lp)); 476 477 addChild(layerTests); 478 479 TestCaseGroup* sampleTests = new TestCaseGroup( 480 getContext(), "samples", "Tests for multisample attachments"); 481 482 static const NumSamplesParams s_samplesParams[] = 483 { 484 { { 0, SAMPLES_NONE, SAMPLES_NONE } }, 485 { { 1, SAMPLES_NONE, SAMPLES_NONE } }, 486 { { 2, SAMPLES_NONE, SAMPLES_NONE } }, 487 { { 0, SAMPLES_TEXTURE, SAMPLES_NONE } }, 488 { { 1, SAMPLES_TEXTURE, SAMPLES_NONE } }, 489 { { 2, SAMPLES_TEXTURE, SAMPLES_NONE } }, 490 { { 2, 1, SAMPLES_NONE } }, 491 { { 2, 2, SAMPLES_NONE } }, 492 { { 0, 0, SAMPLES_TEXTURE } }, 493 { { 1, 2, 0 } }, 494 { { 2, 2, 0 } }, 495 { { 1, 1, 1 } }, 496 { { 1, 2, 4 } }, 497 }; 498 499 for (const NumSamplesParams* lp = DE_ARRAY_BEGIN(s_samplesParams); 500 lp != DE_ARRAY_END(s_samplesParams); 501 ++lp) 502 sampleTests->addChild(new NumSamplesTest(m_fboc, *lp)); 503 504 addChild(sampleTests); 505 } 506 507 TestGroup::TestGroup (Context& ctx) 508 : TestCaseGroup (ctx, "completeness", "Completeness tests") 509 , m_checkerFactory () 510 , m_fboc (ctx.getTestContext(), ctx.getRenderContext(), m_checkerFactory) 511 { 512 const FormatEntries stdRange = GLS_ARRAY_RANGE(s_es3Formats); 513 const FormatExtEntries extRange = GLS_ARRAY_RANGE(s_es3ExtFormats); 514 515 m_fboc.addFormats(stdRange); 516 m_fboc.addExtFormats(extRange); 517 m_fboc.setHaveMulticolorAtts(true); // Vanilla ES3 has multiple color attachments 518 } 519 520 tcu::TestCaseGroup* createFboCompletenessTests (Context& context) 521 { 522 return new TestGroup(context); 523 } 524 525 } // Functional 526 } // gles3 527 } // deqp 528