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 Common object lifetime tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "glsLifetimeTests.hpp" 25 26 #include "deString.h" 27 #include "deRandom.hpp" 28 #include "deSTLUtil.hpp" 29 #include "deStringUtil.hpp" 30 #include "tcuRGBA.hpp" 31 #include "tcuImageCompare.hpp" 32 #include "tcuRenderTarget.hpp" 33 #include "tcuStringTemplate.hpp" 34 #include "tcuTestLog.hpp" 35 #include "gluDrawUtil.hpp" 36 #include "gluObjectWrapper.hpp" 37 #include "gluPixelTransfer.hpp" 38 #include "gluShaderProgram.hpp" 39 #include "gluDefs.hpp" 40 #include "gluTextureUtil.hpp" 41 #include "gluStrUtil.hpp" 42 #include "glwFunctions.hpp" 43 44 #include <vector> 45 #include <map> 46 #include <algorithm> 47 #include <sstream> 48 49 namespace deqp 50 { 51 namespace gls 52 { 53 namespace LifetimeTests 54 { 55 namespace details 56 { 57 58 using std::map; 59 using std::string; 60 using std::ostringstream; 61 using de::Random; 62 using tcu::RenderTarget; 63 using tcu::RGBA; 64 using tcu::StringTemplate; 65 using tcu::TestCase; 66 typedef TestCase::IterateResult IterateResult; 67 using tcu::TestLog; 68 using tcu::ScopedLogSection; 69 using glu::Program; 70 using glu::Shader; 71 using glu::Framebuffer; 72 using glu::SHADERTYPE_VERTEX; 73 using glu::SHADERTYPE_FRAGMENT; 74 using namespace glw; 75 76 enum { VIEWPORT_SIZE = 128, FRAMEBUFFER_SIZE = 128 }; 77 78 GLint getInteger (ContextWrapper& gl, GLenum queryParam) 79 { 80 GLint ret = 0; 81 GLU_CHECK_CALL_ERROR( 82 gl.glGetIntegerv(queryParam, &ret), 83 gl.glGetError()); 84 gl.log() << TestLog::Message << "// Single integer output: " << ret << TestLog::EndMessage; 85 return ret; 86 } 87 88 #define GLSL100_SRC(BODY) ("#version 100\n" #BODY "\n") 89 90 static const char* const s_vertexShaderSrc = GLSL100_SRC( 91 attribute vec2 pos; 92 void main() 93 { 94 gl_Position = vec4(pos.xy, 0.0, 1.0); 95 } 96 ); 97 98 static const char* const s_fragmentShaderSrc = GLSL100_SRC( 99 void main() 100 { 101 gl_FragColor = vec4(1.0); 102 } 103 ); 104 105 class CheckedShader : public Shader 106 { 107 public: 108 CheckedShader (const RenderContext& renderCtx, glu::ShaderType type, const string& src) 109 : Shader (renderCtx, type) 110 { 111 const char* const srcStr = src.c_str(); 112 setSources(1, &srcStr, DE_NULL); 113 compile(); 114 TCU_CHECK(getCompileStatus()); 115 } 116 }; 117 118 class CheckedProgram : public Program 119 { 120 public: 121 CheckedProgram (const RenderContext& renderCtx, GLuint vtxShader, GLuint fragShader) 122 : Program (renderCtx) 123 { 124 attachShader(vtxShader); 125 attachShader(fragShader); 126 link(); 127 TCU_CHECK(getLinkStatus()); 128 } 129 }; 130 131 ContextWrapper::ContextWrapper (const Context& ctx) 132 : CallLogWrapper (ctx.gl(), ctx.log()) 133 , m_ctx (ctx) 134 { 135 enableLogging(true); 136 } 137 138 void SimpleBinder::bind (GLuint name) 139 { 140 (this->*m_bindFunc)(m_bindTarget, name); 141 } 142 143 GLuint SimpleBinder::getBinding (void) 144 { 145 return getInteger(*this, m_bindingParam); 146 } 147 148 GLuint SimpleType::gen (void) 149 { 150 GLuint ret; 151 (this->*m_genFunc)(1, &ret); 152 return ret; 153 } 154 155 class VertexArrayBinder : public SimpleBinder 156 { 157 public: 158 VertexArrayBinder (Context& ctx) 159 : SimpleBinder (ctx, 0, GL_NONE, GL_VERTEX_ARRAY_BINDING, true) {} 160 void bind (GLuint name) { glBindVertexArray(name); } 161 }; 162 163 class QueryBinder : public Binder 164 { 165 public: 166 QueryBinder (Context& ctx) : Binder(ctx) {} 167 void bind (GLuint name) 168 { 169 if (name != 0) 170 glBeginQuery(GL_ANY_SAMPLES_PASSED, name); 171 else 172 glEndQuery(GL_ANY_SAMPLES_PASSED); 173 } 174 GLuint getBinding (void) { return 0; } 175 }; 176 177 bool ProgramType::isDeleteFlagged (GLuint name) 178 { 179 GLint deleteFlagged = 0; 180 glGetProgramiv(name, GL_DELETE_STATUS, &deleteFlagged); 181 return deleteFlagged != 0; 182 } 183 184 bool ShaderType::isDeleteFlagged (GLuint name) 185 { 186 GLint deleteFlagged = 0; 187 glGetShaderiv(name, GL_DELETE_STATUS, &deleteFlagged); 188 return deleteFlagged != 0; 189 } 190 191 void setupFbo (const Context& ctx, GLuint seed, GLuint fbo) 192 { 193 const Functions& gl = ctx.getRenderContext().getFunctions(); 194 195 GLU_CHECK_CALL_ERROR(gl.bindFramebuffer(GL_FRAMEBUFFER, fbo), 196 gl.getError()); 197 198 if (seed == 0) 199 { 200 gl.clearColor(0.0, 0.0, 0.0, 1.0); 201 GLU_CHECK_CALL_ERROR(gl.clear(GL_COLOR_BUFFER_BIT), gl.getError()); 202 } 203 else 204 { 205 Random rnd (seed); 206 const GLsizei width = rnd.getInt(0, FRAMEBUFFER_SIZE); 207 const GLsizei height = rnd.getInt(0, FRAMEBUFFER_SIZE); 208 const GLint x = rnd.getInt(0, FRAMEBUFFER_SIZE - width); 209 const GLint y = rnd.getInt(0, FRAMEBUFFER_SIZE - height); 210 const GLfloat r1 = rnd.getFloat(); 211 const GLfloat g1 = rnd.getFloat(); 212 const GLfloat b1 = rnd.getFloat(); 213 const GLfloat a1 = rnd.getFloat(); 214 const GLfloat r2 = rnd.getFloat(); 215 const GLfloat g2 = rnd.getFloat(); 216 const GLfloat b2 = rnd.getFloat(); 217 const GLfloat a2 = rnd.getFloat(); 218 219 GLU_CHECK_CALL_ERROR(gl.clearColor(r1, g1, b1, a1), gl.getError()); 220 GLU_CHECK_CALL_ERROR(gl.clear(GL_COLOR_BUFFER_BIT), gl.getError()); 221 gl.scissor(x, y, width, height); 222 gl.enable(GL_SCISSOR_TEST); 223 gl.clearColor(r2, g2, b2, a2); 224 gl.clear(GL_COLOR_BUFFER_BIT); 225 gl.disable(GL_SCISSOR_TEST); 226 } 227 228 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 229 GLU_CHECK_ERROR(gl.getError()); 230 } 231 232 void drawFbo (const Context& ctx, GLuint fbo, Surface& dst) 233 { 234 const RenderContext& renderCtx = ctx.getRenderContext(); 235 const Functions& gl = renderCtx.getFunctions(); 236 237 GLU_CHECK_CALL_ERROR( 238 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo), 239 gl.getError()); 240 241 dst.setSize(FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE); 242 glu::readPixels(renderCtx, 0, 0, dst.getAccess()); 243 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels from framebuffer"); 244 245 GLU_CHECK_CALL_ERROR( 246 gl.bindFramebuffer(GL_FRAMEBUFFER, 0), 247 gl.getError()); 248 } 249 250 GLuint getFboAttachment (const Functions& gl, GLuint fbo, GLenum requiredType) 251 { 252 GLint type = 0, name = 0; 253 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); 254 GLU_CHECK_CALL_ERROR( 255 gl.getFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 256 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, 257 &type), 258 gl.getError()); 259 260 if (GLenum(type) != requiredType || GLenum(type) == GL_NONE) 261 return 0; 262 263 GLU_CHECK_CALL_ERROR( 264 gl.getFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 265 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, 266 &name), 267 gl.getError()); 268 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 269 GLU_CHECK_ERROR(gl.getError()); 270 271 return name; 272 } 273 274 void FboAttacher::initAttachment (GLuint seed, GLuint element) 275 { 276 Binder& binder = *getElementType().binder(); 277 Framebuffer fbo(getRenderContext()); 278 279 enableLogging(false); 280 281 binder.enableLogging(false); 282 binder.bind(element); 283 initStorage(); 284 binder.bind(0); 285 binder.enableLogging(true); 286 287 attach(element, *fbo); 288 setupFbo(getContext(), seed, *fbo); 289 detach(element, *fbo); 290 291 enableLogging(true); 292 293 log() << TestLog::Message 294 << "// Drew to " << getElementType().getName() << " " << element 295 << " with seed " << seed << "." 296 << TestLog::EndMessage; 297 } 298 299 void FboInputAttacher::drawContainer (GLuint fbo, Surface& dst) 300 { 301 drawFbo(getContext(), fbo, dst); 302 log() << TestLog::Message 303 << "// Read pixels from framebuffer " << fbo << " to output image." 304 << TestLog::EndMessage; 305 } 306 307 void FboOutputAttacher::setupContainer (GLuint seed, GLuint fbo) 308 { 309 setupFbo(getContext(), seed, fbo); 310 log() << TestLog::Message 311 << "// Drew to framebuffer " << fbo << " with seed " << seed << "." 312 << TestLog::EndMessage; 313 } 314 315 void FboOutputAttacher::drawAttachment (GLuint element, Surface& dst) 316 { 317 Framebuffer fbo(getRenderContext()); 318 m_attacher.enableLogging(false); 319 m_attacher.attach(element, *fbo); 320 drawFbo(getContext(), *fbo, dst); 321 m_attacher.detach(element, *fbo); 322 m_attacher.enableLogging(true); 323 log() << TestLog::Message 324 << "// Read pixels from " << m_attacher.getElementType().getName() << " " << element 325 << " to output image." 326 << TestLog::EndMessage; 327 GLU_CHECK_ERROR(gl().getError()); 328 } 329 330 void TextureFboAttacher::attach (GLuint texture, GLuint fbo) 331 { 332 GLU_CHECK_CALL_ERROR( 333 glBindFramebuffer(GL_FRAMEBUFFER, fbo), 334 gl().getError()); 335 GLU_CHECK_CALL_ERROR( 336 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 337 GL_TEXTURE_2D, texture, 0), 338 gl().getError()); 339 GLU_CHECK_CALL_ERROR( 340 glBindFramebuffer(GL_FRAMEBUFFER, 0), 341 gl().getError()); 342 } 343 344 void TextureFboAttacher::detach (GLuint texture, GLuint fbo) 345 { 346 DE_UNREF(texture); 347 GLU_CHECK_CALL_ERROR( 348 glBindFramebuffer(GL_FRAMEBUFFER, fbo), 349 gl().getError()); 350 GLU_CHECK_CALL_ERROR( 351 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0), 352 gl().getError()); 353 GLU_CHECK_CALL_ERROR( 354 glBindFramebuffer(GL_FRAMEBUFFER, 0), 355 gl().getError()); 356 } 357 358 GLuint TextureFboAttacher::getAttachment (GLuint fbo) 359 { 360 return getFboAttachment(gl(), fbo, GL_TEXTURE); 361 } 362 363 static bool isTextureFormatColorRenderable (const glu::RenderContext& renderCtx, const glu::TransferFormat& format) 364 { 365 const glw::Functions& gl = renderCtx.getFunctions(); 366 deUint32 curFbo = ~0u; 367 deUint32 curTex = ~0u; 368 deUint32 testFbo = 0u; 369 deUint32 testTex = 0u; 370 GLenum status = GL_NONE; 371 372 GLU_CHECK_GLW_CALL(gl, getIntegerv(GL_FRAMEBUFFER_BINDING, (deInt32*)&curFbo)); 373 GLU_CHECK_GLW_CALL(gl, getIntegerv(GL_TEXTURE_BINDING_2D, (deInt32*)&curTex)); 374 375 try 376 { 377 GLU_CHECK_GLW_CALL(gl, genTextures(1, &testTex)); 378 GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, testTex)); 379 GLU_CHECK_GLW_CALL(gl, texImage2D(GL_TEXTURE_2D, 0, format.format, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE, 0, 380 format.format, format.dataType, DE_NULL)); 381 382 GLU_CHECK_GLW_CALL(gl, genFramebuffers(1, &testFbo)); 383 GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, testFbo)); 384 GLU_CHECK_GLW_CALL(gl, framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, testTex, 0)); 385 386 status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); 387 GLU_CHECK_GLW_MSG(gl, "glCheckFramebufferStatus(GL_FRAMEBUFFER)"); 388 389 GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, curTex)); 390 GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, curFbo)); 391 392 GLU_CHECK_GLW_CALL(gl, deleteTextures(1, &testTex)); 393 GLU_CHECK_GLW_CALL(gl, deleteFramebuffers(1, &testFbo)); 394 } 395 catch (...) 396 { 397 if (testTex != 0) 398 gl.deleteTextures(1, &testTex); 399 400 if (testFbo != 0) 401 gl.deleteFramebuffers(1, &testFbo); 402 403 throw; 404 } 405 406 if (status == GL_FRAMEBUFFER_COMPLETE) 407 return true; 408 else if (status == GL_FRAMEBUFFER_UNSUPPORTED) 409 return false; 410 else 411 TCU_THROW(TestError, (std::string("glCheckFramebufferStatus() returned invalid result code ") 412 + de::toString(glu::getFramebufferStatusStr(status))).c_str()); 413 } 414 415 static glu::TransferFormat getRenderableColorTextureFormat (const glu::RenderContext& renderCtx) 416 { 417 if (glu::contextSupports(renderCtx.getType(), glu::ApiType::es(3,0))) 418 return glu::TransferFormat(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4); 419 420 { 421 const glu::TransferFormat candidates[] = 422 { 423 glu::TransferFormat(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4), 424 glu::TransferFormat(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1), 425 glu::TransferFormat(GL_RGB, GL_UNSIGNED_SHORT_5_6_5), 426 glu::TransferFormat(GL_RGBA, GL_UNSIGNED_BYTE), 427 }; 428 429 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(candidates); ++ndx) 430 { 431 if (isTextureFormatColorRenderable(renderCtx, candidates[ndx])) 432 return candidates[ndx]; 433 } 434 } 435 436 return glu::TransferFormat(GL_NONE, GL_NONE); 437 } 438 439 void TextureFboAttacher::initStorage (void) 440 { 441 const glu::TransferFormat format = getRenderableColorTextureFormat(getRenderContext()); 442 443 if (format.format == GL_NONE) 444 TCU_THROW(NotSupportedError, "No renderable texture format found"); 445 446 GLU_CHECK_CALL_ERROR( 447 glTexImage2D(GL_TEXTURE_2D, 0, format.format, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE, 0, 448 format.format, format.dataType, DE_NULL), 449 gl().getError()); 450 } 451 452 static bool isRenderbufferFormatColorRenderable (const glu::RenderContext& renderCtx, const deUint32 format) 453 { 454 const glw::Functions& gl = renderCtx.getFunctions(); 455 deUint32 curFbo = ~0u; 456 deUint32 curRbo = ~0u; 457 deUint32 testFbo = 0u; 458 deUint32 testRbo = 0u; 459 GLenum status = GL_NONE; 460 461 GLU_CHECK_GLW_CALL(gl, getIntegerv(GL_FRAMEBUFFER_BINDING, (deInt32*)&curFbo)); 462 GLU_CHECK_GLW_CALL(gl, getIntegerv(GL_RENDERBUFFER_BINDING, (deInt32*)&curRbo)); 463 464 try 465 { 466 GLU_CHECK_GLW_CALL(gl, genRenderbuffers(1, &testRbo)); 467 GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, testRbo)); 468 GLU_CHECK_GLW_CALL(gl, renderbufferStorage(GL_RENDERBUFFER, format, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE)); 469 470 GLU_CHECK_GLW_CALL(gl, genFramebuffers(1, &testFbo)); 471 GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, testFbo)); 472 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, testRbo)); 473 474 status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); 475 GLU_CHECK_GLW_MSG(gl, "glCheckFramebufferStatus(GL_FRAMEBUFFER)"); 476 477 GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, curRbo)); 478 GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, curFbo)); 479 480 GLU_CHECK_GLW_CALL(gl, deleteRenderbuffers(1, &testRbo)); 481 GLU_CHECK_GLW_CALL(gl, deleteFramebuffers(1, &testFbo)); 482 } 483 catch (...) 484 { 485 if (testRbo != 0) 486 gl.deleteRenderbuffers(1, &testRbo); 487 488 if (testFbo != 0) 489 gl.deleteFramebuffers(1, &testFbo); 490 491 throw; 492 } 493 494 if (status == GL_FRAMEBUFFER_COMPLETE) 495 return true; 496 else if (status == GL_FRAMEBUFFER_UNSUPPORTED) 497 return false; 498 else 499 TCU_THROW(TestError, (std::string("glCheckFramebufferStatus() returned invalid result code ") 500 + de::toString(glu::getFramebufferStatusStr(status))).c_str()); 501 } 502 503 static deUint32 getRenderableColorRenderbufferFormat (const glu::RenderContext& renderCtx) 504 { 505 if (glu::contextSupports(renderCtx.getType(), glu::ApiType::es(3,0))) 506 return GL_RGBA4; 507 508 { 509 const deUint32 candidates[] = 510 { 511 GL_RGBA4, 512 GL_RGB5_A1, 513 GL_RGB565, 514 }; 515 516 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(candidates); ++ndx) 517 { 518 if (isRenderbufferFormatColorRenderable(renderCtx, candidates[ndx])) 519 return candidates[ndx]; 520 } 521 } 522 523 return GL_NONE; 524 } 525 526 void RboFboAttacher::initStorage (void) 527 { 528 const deUint32 format = getRenderableColorRenderbufferFormat(getRenderContext()); 529 530 if (format == GL_NONE) 531 TCU_THROW(TestError, "No color-renderable renderbuffer format found"); 532 533 GLU_CHECK_CALL_ERROR( 534 glRenderbufferStorage(GL_RENDERBUFFER, format, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE), 535 gl().getError()); 536 } 537 538 void RboFboAttacher::attach (GLuint rbo, GLuint fbo) 539 { 540 GLU_CHECK_CALL_ERROR( 541 glBindFramebuffer(GL_FRAMEBUFFER, fbo), 542 gl().getError()); 543 GLU_CHECK_CALL_ERROR( 544 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo), 545 gl().getError()); 546 GLU_CHECK_CALL_ERROR( 547 glBindFramebuffer(GL_FRAMEBUFFER, 0), 548 gl().getError()); 549 } 550 551 void RboFboAttacher::detach (GLuint rbo, GLuint fbo) 552 { 553 DE_UNREF(rbo); 554 GLU_CHECK_CALL_ERROR( 555 glBindFramebuffer(GL_FRAMEBUFFER, fbo), 556 gl().getError()); 557 GLU_CHECK_CALL_ERROR( 558 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0), 559 gl().getError()); 560 GLU_CHECK_CALL_ERROR( 561 glBindFramebuffer(GL_FRAMEBUFFER, 0), 562 gl().getError()); 563 } 564 565 GLuint RboFboAttacher::getAttachment (GLuint fbo) 566 { 567 return getFboAttachment(gl(), fbo, GL_RENDERBUFFER); 568 } 569 570 static const char* const s_fragmentShaderTemplate = GLSL100_SRC( 571 void main() 572 { 573 gl_FragColor = vec4(${RED}, ${GREEN}, ${BLUE}, 1.0); 574 } 575 ); 576 577 void ShaderProgramAttacher::initAttachment (GLuint seed, GLuint shader) 578 { 579 using de::insert; 580 using de::floatToString; 581 582 Random rnd(seed); 583 map<string, string> params; 584 const StringTemplate sourceTmpl (s_fragmentShaderTemplate); 585 586 insert(params, "RED", floatToString(rnd.getFloat(), 4)); 587 insert(params, "GREEN", floatToString(rnd.getFloat(), 4)); 588 insert(params, "BLUE", floatToString(rnd.getFloat(), 4)); 589 590 { 591 const string source = sourceTmpl.specialize(params); 592 const char* const sourceStr = source.c_str(); 593 594 GLU_CHECK_CALL_ERROR(glShaderSource(shader, 1, &sourceStr, DE_NULL), gl().getError()); 595 GLU_CHECK_CALL_ERROR(glCompileShader(shader), gl().getError()); 596 597 { 598 GLint compileStatus = 0; 599 gl().getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); 600 TCU_CHECK_MSG(compileStatus != 0, sourceStr); 601 } 602 } 603 } 604 605 void ShaderProgramAttacher::attach (GLuint shader, GLuint program) 606 { 607 GLU_CHECK_CALL_ERROR( 608 glAttachShader(program, shader), 609 gl().getError()); 610 } 611 612 void ShaderProgramAttacher::detach (GLuint shader, GLuint program) 613 { 614 GLU_CHECK_CALL_ERROR( 615 glDetachShader(program, shader), 616 gl().getError()); 617 } 618 619 GLuint ShaderProgramAttacher::getAttachment (GLuint program) 620 { 621 GLuint shaders[2] = { 0, 0 }; 622 const GLsizei shadersLen = DE_LENGTH_OF_ARRAY(shaders); 623 GLsizei numShaders = 0; 624 GLuint ret = 0; 625 626 gl().getAttachedShaders(program, shadersLen, &numShaders, shaders); 627 628 // There should ever be at most one attached shader in normal use, but if 629 // something is wrong, the temporary vertex shader might not have been 630 // detached properly, so let's find the fragment shader explicitly. 631 for (int ndx = 0; ndx < de::min<GLsizei>(shadersLen, numShaders); ++ndx) 632 { 633 GLint shaderType = GL_NONE; 634 gl().getShaderiv(shaders[ndx], GL_SHADER_TYPE, &shaderType); 635 636 if (shaderType == GL_FRAGMENT_SHADER) 637 { 638 ret = shaders[ndx]; 639 break; 640 } 641 } 642 643 return ret; 644 } 645 646 void setViewport (const RenderContext& renderCtx, const Rectangle& rect) 647 { 648 renderCtx.getFunctions().viewport(rect.x, rect.y, rect.width, rect.height); 649 } 650 651 void readRectangle (const RenderContext& renderCtx, const Rectangle& rect, Surface& dst) 652 { 653 dst.setSize(rect.width, rect.height); 654 glu::readPixels(renderCtx, rect.x, rect.y, dst.getAccess()); 655 } 656 657 Rectangle randomViewport (const RenderContext& ctx, GLint maxWidth, GLint maxHeight, 658 Random& rnd) 659 { 660 const RenderTarget& target = ctx.getRenderTarget(); 661 const GLint width = de::min(target.getWidth(), maxWidth); 662 const GLint xOff = rnd.getInt(0, target.getWidth() - width); 663 const GLint height = de::min(target.getHeight(), maxHeight); 664 const GLint yOff = rnd.getInt(0, target.getHeight() - height); 665 666 return Rectangle(xOff, yOff, width, height); 667 } 668 669 void ShaderProgramInputAttacher::drawContainer (GLuint program, Surface& dst) 670 { 671 static const float s_vertices[6] = { -1.0, 0.0, 1.0, 1.0, 0.0, -1.0 }; 672 Random rnd (program); 673 CheckedShader vtxShader (getRenderContext(), 674 SHADERTYPE_VERTEX, s_vertexShaderSrc); 675 const Rectangle viewport = randomViewport(getRenderContext(), 676 VIEWPORT_SIZE, VIEWPORT_SIZE, rnd); 677 678 gl().attachShader(program, vtxShader.getShader()); 679 gl().linkProgram(program); 680 681 { 682 GLint linkStatus = 0; 683 gl().getProgramiv(program, GL_LINK_STATUS, &linkStatus); 684 TCU_CHECK(linkStatus != 0); 685 } 686 687 log() << TestLog::Message 688 << "// Attached a temporary vertex shader and linked program " << program 689 << TestLog::EndMessage; 690 691 setViewport(getRenderContext(), viewport); 692 log() << TestLog::Message << "// Positioned viewport randomly" << TestLog::EndMessage; 693 694 glUseProgram(program); 695 { 696 GLint posLoc = gl().getAttribLocation(program, "pos"); 697 TCU_CHECK(posLoc >= 0); 698 699 gl().enableVertexAttribArray(posLoc); 700 701 gl().clearColor(0, 0, 0, 1); 702 gl().clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 703 gl().vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, s_vertices); 704 gl().drawArrays(GL_TRIANGLES, 0, 3); 705 706 gl().disableVertexAttribArray(posLoc); 707 log () << TestLog::Message << "// Drew a fixed triangle" << TestLog::EndMessage; 708 } 709 glUseProgram(0); 710 711 readRectangle(getRenderContext(), viewport, dst); 712 log() << TestLog::Message << "// Copied viewport to output image" << TestLog::EndMessage; 713 714 gl().detachShader(program, vtxShader.getShader()); 715 log() << TestLog::Message << "// Removed temporary vertex shader" << TestLog::EndMessage; 716 } 717 718 ES2Types::ES2Types (const Context& ctx) 719 : Types (ctx) 720 , m_bufferBind (ctx, &CallLogWrapper::glBindBuffer, 721 GL_ARRAY_BUFFER, GL_ARRAY_BUFFER_BINDING) 722 , m_bufferType (ctx, "buffer", &CallLogWrapper::glGenBuffers, 723 &CallLogWrapper::glDeleteBuffers, 724 &CallLogWrapper::glIsBuffer, &m_bufferBind) 725 , m_textureBind (ctx, &CallLogWrapper::glBindTexture, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D) 726 , m_textureType (ctx, "texture", &CallLogWrapper::glGenTextures, 727 &CallLogWrapper::glDeleteTextures, 728 &CallLogWrapper::glIsTexture, &m_textureBind) 729 , m_rboBind (ctx, &CallLogWrapper::glBindRenderbuffer, 730 GL_RENDERBUFFER, GL_RENDERBUFFER_BINDING) 731 , m_rboType (ctx, "renderbuffer", 732 &CallLogWrapper::glGenRenderbuffers, 733 &CallLogWrapper::glDeleteRenderbuffers, 734 &CallLogWrapper::glIsRenderbuffer, &m_rboBind) 735 , m_fboBind (ctx, &CallLogWrapper::glBindFramebuffer, 736 GL_FRAMEBUFFER, GL_FRAMEBUFFER_BINDING) 737 , m_fboType (ctx, "framebuffer", 738 &CallLogWrapper::glGenFramebuffers, 739 &CallLogWrapper::glDeleteFramebuffers, 740 &CallLogWrapper::glIsFramebuffer, &m_fboBind) 741 , m_shaderType (ctx) 742 , m_programType (ctx) 743 , m_texFboAtt (ctx, m_textureType, m_fboType) 744 , m_texFboInAtt (m_texFboAtt) 745 , m_texFboOutAtt(m_texFboAtt) 746 , m_rboFboAtt (ctx, m_rboType, m_fboType) 747 , m_rboFboInAtt (m_rboFboAtt) 748 , m_rboFboOutAtt(m_rboFboAtt) 749 , m_shaderAtt (ctx, m_shaderType, m_programType) 750 , m_shaderInAtt (m_shaderAtt) 751 { 752 Type* const types[] = 753 { 754 &m_bufferType, &m_textureType, &m_rboType, &m_fboType, &m_shaderType, &m_programType 755 }; 756 m_types.insert(m_types.end(), DE_ARRAY_BEGIN(types), DE_ARRAY_END(types)); 757 758 m_attachers.push_back(&m_texFboAtt); 759 m_attachers.push_back(&m_rboFboAtt); 760 m_attachers.push_back(&m_shaderAtt); 761 762 m_inAttachers.push_back(&m_texFboInAtt); 763 m_inAttachers.push_back(&m_rboFboInAtt); 764 m_inAttachers.push_back(&m_shaderInAtt); 765 766 m_outAttachers.push_back(&m_texFboOutAtt); 767 m_outAttachers.push_back(&m_rboFboOutAtt); 768 } 769 770 class Name 771 { 772 public: 773 Name (Type& type) : m_type(type), m_name(type.gen()) {} 774 Name (Type& type, GLuint name) : m_type(type), m_name(name) {} 775 ~Name (void) { m_type.release(m_name); } 776 GLuint operator* (void) const { return m_name; } 777 778 private: 779 Type& m_type; 780 const GLuint m_name; 781 }; 782 783 class ResultCollector 784 { 785 public: 786 ResultCollector (TestContext& testCtx); 787 bool check (bool cond, const char* msg); 788 void fail (const char* msg); 789 void warn (const char* msg); 790 ~ResultCollector (void); 791 792 private: 793 void addResult (qpTestResult result, const char* msg); 794 795 TestContext& m_testCtx; 796 TestLog& m_log; 797 qpTestResult m_result; 798 const char* m_message; 799 }; 800 801 ResultCollector::ResultCollector (TestContext& testCtx) 802 : m_testCtx (testCtx) 803 , m_log (testCtx.getLog()) 804 , m_result (QP_TEST_RESULT_PASS) 805 , m_message ("Pass") 806 { 807 } 808 809 bool ResultCollector::check (bool cond, const char* msg) 810 { 811 if (!cond) 812 fail(msg); 813 return cond; 814 } 815 816 void ResultCollector::addResult (qpTestResult result, const char* msg) 817 { 818 m_log << TestLog::Message << "// Fail: " << msg << TestLog::EndMessage; 819 if (m_result == QP_TEST_RESULT_PASS) 820 { 821 m_result = result; 822 m_message = msg; 823 } 824 else 825 { 826 if (result == QP_TEST_RESULT_FAIL) 827 m_result = result; 828 m_message = "Multiple problems, see log for details"; 829 } 830 } 831 832 void ResultCollector::fail (const char* msg) 833 { 834 addResult(QP_TEST_RESULT_FAIL, msg); 835 } 836 837 void ResultCollector::warn (const char* msg) 838 { 839 addResult(QP_TEST_RESULT_QUALITY_WARNING, msg); 840 } 841 842 ResultCollector::~ResultCollector (void) 843 { 844 m_testCtx.setTestResult(m_result, m_message); 845 } 846 847 class TestBase : public TestCase, protected CallLogWrapper 848 { 849 protected: 850 TestBase (const char* name, 851 const char* description, 852 const Context& ctx); 853 854 // Copy ContextWrapper since MI (except for CallLogWrapper) is a no-no. 855 const Context& getContext (void) const { return m_ctx; } 856 const RenderContext& getRenderContext (void) const { return m_ctx.getRenderContext(); } 857 const Functions& gl (void) const { return m_ctx.gl(); } 858 TestLog& log (void) const { return m_ctx.log(); } 859 void init (void); 860 861 Context m_ctx; 862 Random m_rnd; 863 }; 864 865 TestBase::TestBase (const char* name, const char* description, const Context& ctx) 866 : TestCase (ctx.getTestContext(), name, description) 867 , CallLogWrapper (ctx.gl(), ctx.log()) 868 , m_ctx (ctx) 869 , m_rnd (deStringHash(name)) 870 { 871 enableLogging(true); 872 } 873 874 void TestBase::init (void) 875 { 876 m_rnd = Random(deStringHash(getName())); 877 } 878 879 class LifeTest : public TestBase 880 { 881 public: 882 typedef void (LifeTest::*TestFunction) (void); 883 884 LifeTest (const char* name, 885 const char* description, 886 Type& type, 887 TestFunction test) 888 : TestBase (name, description, type.getContext()) 889 , m_type (type) 890 , m_test (test) {} 891 892 IterateResult iterate (void); 893 894 void testGen (void); 895 void testDelete (void); 896 void testBind (void); 897 void testDeleteBound (void); 898 void testBindNoGen (void); 899 void testDeleteUsed (void); 900 901 private: 902 Binder& binder (void) { return *m_type.binder(); } 903 904 Type& m_type; 905 TestFunction m_test; 906 }; 907 908 IterateResult LifeTest::iterate (void) 909 { 910 (this->*m_test)(); 911 return STOP; 912 } 913 914 void LifeTest::testGen (void) 915 { 916 ResultCollector errors (getTestContext()); 917 Name name (m_type); 918 919 if (m_type.genCreates()) 920 errors.check(m_type.exists(*name), "Gen* should have created an object, but didn't"); 921 else 922 errors.check(!m_type.exists(*name), "Gen* should not have created an object, but did"); 923 } 924 925 void LifeTest::testDelete (void) 926 { 927 ResultCollector errors (getTestContext()); 928 GLuint name = m_type.gen(); 929 930 m_type.release(name); 931 errors.check(!m_type.exists(name), "Object still exists after deletion"); 932 } 933 934 void LifeTest::testBind (void) 935 { 936 ResultCollector errors (getTestContext()); 937 Name name (m_type); 938 939 binder().bind(*name); 940 GLU_EXPECT_NO_ERROR(gl().getError(), "Bind failed"); 941 errors.check(m_type.exists(*name), "Object does not exist after binding"); 942 binder().bind(0); 943 } 944 945 void LifeTest::testDeleteBound (void) 946 { 947 const GLuint id = m_type.gen(); 948 ResultCollector errors (getTestContext()); 949 950 binder().bind(id); 951 m_type.release(id); 952 953 if (m_type.nameLingers()) 954 { 955 errors.check(gl().getError() == GL_NO_ERROR, "Deleting bound object failed"); 956 errors.check(binder().getBinding() == id, 957 "Deleting bound object did not retain binding"); 958 errors.check(m_type.exists(id), 959 "Deleting bound object made its name invalid"); 960 errors.check(m_type.isDeleteFlagged(id), 961 "Deleting bound object did not flag the object for deletion"); 962 binder().bind(0); 963 } 964 else 965 { 966 errors.check(gl().getError() == GL_NO_ERROR, "Deleting bound object failed"); 967 errors.check(binder().getBinding() == 0, 968 "Deleting bound object did not remove binding"); 969 errors.check(!m_type.exists(id), 970 "Deleting bound object did not make its name invalid"); 971 binder().bind(0); 972 } 973 974 errors.check(binder().getBinding() == 0, "Unbinding didn't remove binding"); 975 errors.check(!m_type.exists(id), "Name is still valid after deleting and unbinding"); 976 } 977 978 void LifeTest::testBindNoGen (void) 979 { 980 ResultCollector errors (getTestContext()); 981 const GLuint id = m_rnd.getUint32(); 982 983 if (!errors.check(!m_type.exists(id), "Randomly chosen identifier already exists")) 984 return; 985 986 Name name (m_type, id); 987 binder().bind(*name); 988 989 if (binder().genRequired()) 990 { 991 errors.check(glGetError() == GL_INVALID_OPERATION, 992 "Did not fail when binding a name not generated by Gen* call"); 993 errors.check(!m_type.exists(*name), 994 "Bind* created an object for a name not generated by a Gen* call"); 995 } 996 else 997 { 998 errors.check(glGetError() == GL_NO_ERROR, 999 "Failed when binding a name not generated by Gen* call"); 1000 errors.check(m_type.exists(*name), 1001 "Object was not created by the Bind* call"); 1002 } 1003 } 1004 1005 void LifeTest::testDeleteUsed (void) 1006 { 1007 ResultCollector errors(getTestContext()); 1008 GLuint programId = 0; 1009 1010 { 1011 CheckedShader vtxShader (getRenderContext(), 1012 SHADERTYPE_VERTEX, s_vertexShaderSrc); 1013 CheckedShader fragShader (getRenderContext(), 1014 SHADERTYPE_FRAGMENT, s_fragmentShaderSrc); 1015 CheckedProgram program (getRenderContext(), 1016 vtxShader.getShader(), fragShader.getShader()); 1017 1018 programId = program.getProgram(); 1019 1020 log() << TestLog::Message << "// Created and linked program " << programId 1021 << TestLog::EndMessage; 1022 GLU_CHECK_CALL_ERROR(glUseProgram(programId), gl().getError()); 1023 1024 log() << TestLog::Message << "// Deleted program " << programId 1025 << TestLog::EndMessage; 1026 } 1027 TCU_CHECK(glIsProgram(programId)); 1028 { 1029 GLint deleteFlagged = 0; 1030 glGetProgramiv(programId, GL_DELETE_STATUS, &deleteFlagged); 1031 errors.check(deleteFlagged != 0, "Program object was not flagged as deleted"); 1032 } 1033 GLU_CHECK_CALL_ERROR(glUseProgram(0), gl().getError()); 1034 errors.check(!gl().isProgram(programId), 1035 "Deleted program name still valid after being made non-current"); 1036 } 1037 1038 class AttachmentTest : public TestBase 1039 { 1040 public: 1041 typedef void (AttachmentTest::*TestFunction) (void); 1042 AttachmentTest (const char* name, 1043 const char* description, 1044 Attacher& attacher, 1045 TestFunction test) 1046 : TestBase (name, description, attacher.getContext()) 1047 , m_attacher (attacher) 1048 , m_test (test) {} 1049 IterateResult iterate (void); 1050 1051 void testDeletedNames (void); 1052 void testDeletedBinding (void); 1053 void testDeletedReattach (void); 1054 1055 private: 1056 Attacher& m_attacher; 1057 const TestFunction m_test; 1058 }; 1059 1060 IterateResult AttachmentTest::iterate (void) 1061 { 1062 (this->*m_test)(); 1063 return STOP; 1064 } 1065 1066 GLuint getAttachment (Attacher& attacher, GLuint container) 1067 { 1068 const GLuint queriedAttachment = attacher.getAttachment(container); 1069 attacher.log() << TestLog::Message 1070 << "// Result of query for " << attacher.getElementType().getName() 1071 << " attached to " << attacher.getContainerType().getName() << " " 1072 << container << ": " << queriedAttachment << "." 1073 << TestLog::EndMessage; 1074 return queriedAttachment; 1075 } 1076 1077 void AttachmentTest::testDeletedNames (void) 1078 { 1079 Type& elemType = m_attacher.getElementType(); 1080 Type& containerType = m_attacher.getContainerType(); 1081 Name container (containerType); 1082 ResultCollector errors (getTestContext()); 1083 GLuint elementId = 0; 1084 1085 { 1086 Name element(elemType); 1087 elementId = *element; 1088 m_attacher.initAttachment(0, *element); 1089 m_attacher.attach(*element, *container); 1090 errors.check(getAttachment(m_attacher, *container) == elementId, 1091 "Attachment name not returned by query even before deletion."); 1092 } 1093 1094 // "Such a container or other context may continue using the object, and 1095 // may still contain state identifying its name as being currently bound" 1096 // 1097 // We here interpret "may" to mean that whenever the container has a 1098 // deleted object attached to it, a query will return that object's former 1099 // name. 1100 errors.check(getAttachment(m_attacher, *container) == elementId, 1101 "Attachment name not returned by query after attachment was deleted."); 1102 1103 if (elemType.nameLingers()) 1104 errors.check(elemType.exists(elementId), 1105 "Attached object name no longer valid after deletion."); 1106 else 1107 errors.check(!elemType.exists(elementId), 1108 "Attached object name still valid after deletion."); 1109 1110 m_attacher.detach(elementId, *container); 1111 errors.check(getAttachment(m_attacher, *container) == 0, 1112 "Attachment name returned by query even after detachment."); 1113 errors.check(!elemType.exists(elementId), 1114 "Deleted attached object name still usable after detachment."); 1115 }; 1116 1117 class InputAttachmentTest : public TestBase 1118 { 1119 public: 1120 InputAttachmentTest (const char* name, 1121 const char* description, 1122 InputAttacher& inputAttacher) 1123 : TestBase (name, description, inputAttacher.getContext()) 1124 , m_inputAttacher (inputAttacher) {} 1125 1126 IterateResult iterate (void); 1127 1128 private: 1129 InputAttacher& m_inputAttacher; 1130 }; 1131 1132 GLuint replaceName (Type& type, GLuint oldName, TestLog& log) 1133 { 1134 const Binder* const binder = type.binder(); 1135 const bool genRequired = binder == DE_NULL || binder->genRequired(); 1136 1137 if (genRequired) 1138 return type.gen(); 1139 1140 log << TestLog::Message 1141 << "// Type does not require Gen* for binding, reusing old id " << oldName << "." 1142 << TestLog::EndMessage; 1143 1144 return oldName; 1145 } 1146 1147 IterateResult InputAttachmentTest::iterate (void) 1148 { 1149 Attacher& attacher = m_inputAttacher.getAttacher(); 1150 Type& containerType = attacher.getContainerType(); 1151 Type& elementType = attacher.getElementType(); 1152 Name container (containerType); 1153 GLuint elementId = 0; 1154 const GLuint refSeed = m_rnd.getUint32(); 1155 const GLuint newSeed = m_rnd.getUint32(); 1156 ResultCollector errors (getTestContext()); 1157 1158 Surface refSurface; // Surface from drawing with refSeed-seeded attachment 1159 Surface delSurface; // Surface from drawing with deleted refSeed attachment 1160 Surface newSurface; // Surface from drawing with newSeed-seeded attachment 1161 1162 log() << TestLog::Message 1163 << "Testing if writing to a newly created object modifies a deleted attachment" 1164 << TestLog::EndMessage; 1165 1166 { 1167 ScopedLogSection section (log(), 1168 "Write to original", "Writing to an original attachment"); 1169 const Name element (elementType); 1170 1171 elementId = *element; 1172 attacher.initAttachment(refSeed, elementId); 1173 attacher.attach(elementId, *container); 1174 m_inputAttacher.drawContainer(*container, refSurface); 1175 // element gets deleted here 1176 log() << TestLog::Message << "// Deleting attachment"; 1177 } 1178 { 1179 ScopedLogSection section (log(), "Write to new", 1180 "Writing to a new attachment after deleting the original"); 1181 const GLuint newId = replaceName(elementType, elementId, log()); 1182 const Name newElement (elementType, newId); 1183 1184 attacher.initAttachment(newSeed, newId); 1185 1186 m_inputAttacher.drawContainer(*container, delSurface); 1187 attacher.detach(elementId, *container); 1188 1189 attacher.attach(newId, *container); 1190 m_inputAttacher.drawContainer(*container, newSurface); 1191 attacher.detach(newId, *container); 1192 } 1193 { 1194 const bool surfacesMatch = tcu::pixelThresholdCompare( 1195 log(), "Reading from deleted", 1196 "Comparison result from reading from a container with a deleted attachment " 1197 "before and after writing to a fresh object.", 1198 refSurface, delSurface, RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT); 1199 1200 errors.check( 1201 surfacesMatch, 1202 "Writing to a fresh object modified the container with a deleted attachment."); 1203 1204 if (!surfacesMatch) 1205 log() << TestLog::Image("New attachment", 1206 "Container state after attached to the fresh object", 1207 newSurface); 1208 } 1209 1210 return STOP; 1211 } 1212 1213 class OutputAttachmentTest : public TestBase 1214 { 1215 public: 1216 OutputAttachmentTest (const char* name, 1217 const char* description, 1218 OutputAttacher& outputAttacher) 1219 : TestBase (name, description, 1220 outputAttacher.getContext()) 1221 , m_outputAttacher (outputAttacher) {} 1222 IterateResult iterate (void); 1223 1224 private: 1225 OutputAttacher& m_outputAttacher; 1226 }; 1227 1228 IterateResult OutputAttachmentTest::iterate (void) 1229 { 1230 Attacher& attacher = m_outputAttacher.getAttacher(); 1231 Type& containerType = attacher.getContainerType(); 1232 Type& elementType = attacher.getElementType(); 1233 Name container (containerType); 1234 GLuint elementId = 0; 1235 const GLuint refSeed = m_rnd.getUint32(); 1236 const GLuint newSeed = m_rnd.getUint32(); 1237 ResultCollector errors (getTestContext()); 1238 Surface refSurface; // Surface drawn from attachment to refSeed container 1239 Surface newSurface; // Surface drawn from attachment to newSeed container 1240 Surface delSurface; // Like newSurface, after writing to a deleted attachment 1241 1242 log() << TestLog::Message 1243 << "Testing if writing to a container with a deleted attachment " 1244 << "modifies a newly created object" 1245 << TestLog::EndMessage; 1246 1247 { 1248 ScopedLogSection section (log(), "Write to existing", 1249 "Writing to a container with an existing attachment"); 1250 const Name element (elementType); 1251 1252 elementId = *element; 1253 attacher.initAttachment(0, elementId); 1254 attacher.attach(elementId, *container); 1255 1256 // For reference purposes, make note of what refSeed looks like. 1257 m_outputAttacher.setupContainer(refSeed, *container); 1258 m_outputAttacher.drawAttachment(elementId, refSurface); 1259 } 1260 { 1261 ScopedLogSection section (log(), "Write to deleted", 1262 "Writing to a container after deletion of attachment"); 1263 const GLuint newId = replaceName(elementType, elementId, log()); 1264 const Name newElement (elementType, newId); 1265 1266 log() << TestLog::Message 1267 << "Creating a new object " << newId 1268 << TestLog::EndMessage; 1269 1270 log() << TestLog::Message 1271 << "Recording state of new object before writing to container" 1272 << TestLog::EndMessage; 1273 attacher.initAttachment(newSeed, newId); 1274 m_outputAttacher.drawAttachment(newId, newSurface); 1275 1276 log() << TestLog::Message 1277 << "Writing to container" 1278 << TestLog::EndMessage; 1279 1280 // Now re-write refSeed to the container. 1281 m_outputAttacher.setupContainer(refSeed, *container); 1282 // Does it affect the newly created attachment object? 1283 m_outputAttacher.drawAttachment(newId, delSurface); 1284 } 1285 attacher.detach(elementId, *container); 1286 1287 const bool surfacesMatch = tcu::pixelThresholdCompare( 1288 log(), "Writing to deleted", 1289 "Comparison result from reading from a fresh object before and after " 1290 "writing to a container with a deleted attachment", 1291 newSurface, delSurface, RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT); 1292 1293 errors.check(surfacesMatch, 1294 "Writing to container with deleted attachment modified a new object."); 1295 1296 if (!surfacesMatch) 1297 log() << TestLog::Image( 1298 "Original attachment", 1299 "Result of container modification on original attachment before deletion.", 1300 refSurface); 1301 return STOP; 1302 }; 1303 1304 struct LifeTestSpec 1305 { 1306 const char* name; 1307 LifeTest::TestFunction func; 1308 bool needBind; 1309 }; 1310 1311 MovePtr<TestCaseGroup> createLifeTestGroup (TestContext& testCtx, 1312 const LifeTestSpec& spec, 1313 const vector<Type*>& types) 1314 { 1315 MovePtr<TestCaseGroup> group(new TestCaseGroup(testCtx, spec.name, spec.name)); 1316 1317 for (vector<Type*>::const_iterator it = types.begin(); it != types.end(); ++it) 1318 { 1319 Type& type = **it; 1320 const char* name = type.getName(); 1321 if (!spec.needBind || type.binder() != DE_NULL) 1322 group->addChild(new LifeTest(name, name, type, spec.func)); 1323 } 1324 1325 return group; 1326 } 1327 1328 static const LifeTestSpec s_lifeTests[] = 1329 { 1330 { "gen", &LifeTest::testGen, false }, 1331 { "delete", &LifeTest::testDelete, false }, 1332 { "bind", &LifeTest::testBind, true }, 1333 { "delete_bound", &LifeTest::testDeleteBound, true }, 1334 { "bind_no_gen", &LifeTest::testBindNoGen, true }, 1335 }; 1336 1337 string attacherName (Attacher& attacher) 1338 { 1339 ostringstream os; 1340 os << attacher.getElementType().getName() << "_" << attacher.getContainerType().getName(); 1341 return os.str(); 1342 } 1343 1344 void addTestCases (TestCaseGroup& group, Types& types) 1345 { 1346 TestContext& testCtx = types.getTestContext(); 1347 1348 for (const LifeTestSpec* it = DE_ARRAY_BEGIN(s_lifeTests); 1349 it != DE_ARRAY_END(s_lifeTests); ++it) 1350 group.addChild(createLifeTestGroup(testCtx, *it, types.getTypes()).release()); 1351 1352 { 1353 TestCaseGroup* const delUsedGroup = 1354 new TestCaseGroup(testCtx, "delete_used", "Delete current program"); 1355 group.addChild(delUsedGroup); 1356 1357 delUsedGroup->addChild( 1358 new LifeTest("program", "program", types.getProgramType(), 1359 &LifeTest::testDeleteUsed)); 1360 } 1361 1362 { 1363 TestCaseGroup* const attGroup = new TestCaseGroup( 1364 testCtx, "attach", "Attachment tests"); 1365 group.addChild(attGroup); 1366 1367 { 1368 TestCaseGroup* const nameGroup = new TestCaseGroup( 1369 testCtx, "deleted_name", "Name of deleted attachment"); 1370 attGroup->addChild(nameGroup); 1371 1372 const vector<Attacher*>& atts = types.getAttachers(); 1373 for (vector<Attacher*>::const_iterator it = atts.begin(); it != atts.end(); ++it) 1374 { 1375 const string name = attacherName(**it); 1376 nameGroup->addChild(new AttachmentTest(name.c_str(), name.c_str(), **it, 1377 &AttachmentTest::testDeletedNames)); 1378 } 1379 } 1380 { 1381 TestCaseGroup* inputGroup = new TestCaseGroup( 1382 testCtx, "deleted_input", "Input from deleted attachment"); 1383 attGroup->addChild(inputGroup); 1384 1385 const vector<InputAttacher*>& inAtts = types.getInputAttachers(); 1386 for (vector<InputAttacher*>::const_iterator it = inAtts.begin(); 1387 it != inAtts.end(); ++it) 1388 { 1389 const string name = attacherName((*it)->getAttacher()); 1390 inputGroup->addChild(new InputAttachmentTest(name.c_str(), name.c_str(), **it)); 1391 } 1392 } 1393 { 1394 TestCaseGroup* outputGroup = new TestCaseGroup( 1395 testCtx, "deleted_output", "Output to deleted attachment"); 1396 attGroup->addChild(outputGroup); 1397 1398 const vector<OutputAttacher*>& outAtts = types.getOutputAttachers(); 1399 for (vector<OutputAttacher*>::const_iterator it = outAtts.begin(); 1400 it != outAtts.end(); ++it) 1401 { 1402 string name = attacherName((*it)->getAttacher()); 1403 outputGroup->addChild(new OutputAttachmentTest(name.c_str(), name.c_str(), 1404 **it)); 1405 } 1406 } 1407 } 1408 } 1409 1410 } // details 1411 } // LifetimeTests 1412 } // gls 1413 } // deqp 1414