1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief Common object lifetime tests.
22 *//*--------------------------------------------------------------------*/
24 #include "glsLifetimeTests.hpp"
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 "glwFunctions.hpp"
51 namespace LifetimeTests
58 using std::ostringstream;
60 using tcu::RenderTarget;
62 using tcu::StringTemplate;
64 typedef TestCase::IterateResult IterateResult;
66 using tcu::ScopedLogSection;
69 using glu::Framebuffer;
70 using glu::SHADERTYPE_VERTEX;
71 using glu::SHADERTYPE_FRAGMENT;
74 enum { VIEWPORT_SIZE = 128, FRAMEBUFFER_SIZE = 128 };
76 GLint getInteger (ContextWrapper& gl, GLenum queryParam)
80 gl.glGetIntegerv(queryParam, &ret),
82 gl.log() << TestLog::Message << "// Single integer output: " << ret << TestLog::EndMessage;
86 #define GLSL100_SRC(BODY) ("#version 100\n" #BODY "\n")
88 static const char* const s_vertexShaderSrc = GLSL100_SRC(
92 gl_Position = vec4(pos.xy, 0.0, 1.0);
96 static const char* const s_fragmentShaderSrc = GLSL100_SRC(
99 gl_FragColor = vec4(1.0);
103 class CheckedShader : public Shader
106 CheckedShader (const RenderContext& renderCtx, glu::ShaderType type, const string& src)
107 : Shader (renderCtx, type)
109 const char* const srcStr = src.c_str();
110 setSources(1, &srcStr, DE_NULL);
112 TCU_CHECK(getCompileStatus());
116 class CheckedProgram : public Program
119 CheckedProgram (const RenderContext& renderCtx, GLuint vtxShader, GLuint fragShader)
120 : Program (renderCtx)
122 attachShader(vtxShader);
123 attachShader(fragShader);
125 TCU_CHECK(getLinkStatus());
129 ContextWrapper::ContextWrapper (const Context& ctx)
130 : CallLogWrapper (ctx.gl(), ctx.log())
136 void SimpleBinder::bind (GLuint name)
138 (this->*m_bindFunc)(m_bindTarget, name);
141 GLuint SimpleBinder::getBinding (void)
143 return getInteger(*this, m_bindingParam);
146 GLuint SimpleType::gen (void)
149 (this->*m_genFunc)(1, &ret);
153 class VertexArrayBinder : public SimpleBinder
156 VertexArrayBinder (Context& ctx)
157 : SimpleBinder (ctx, 0, GL_NONE, GL_VERTEX_ARRAY_BINDING, true) {}
158 void bind (GLuint name) { glBindVertexArray(name); }
161 class QueryBinder : public Binder
164 QueryBinder (Context& ctx) : Binder(ctx) {}
165 void bind (GLuint name)
168 glBeginQuery(GL_ANY_SAMPLES_PASSED, name);
170 glEndQuery(GL_ANY_SAMPLES_PASSED);
172 GLuint getBinding (void) { return 0; }
175 bool ProgramType::isDeleteFlagged (GLuint name)
177 GLint deleteFlagged = 0;
178 glGetProgramiv(name, GL_DELETE_STATUS, &deleteFlagged);
179 return deleteFlagged != 0;
182 bool ShaderType::isDeleteFlagged (GLuint name)
184 GLint deleteFlagged = 0;
185 glGetShaderiv(name, GL_DELETE_STATUS, &deleteFlagged);
186 return deleteFlagged != 0;
189 void setupFbo (const Context& ctx, GLuint seed, GLuint fbo)
191 const Functions& gl = ctx.getRenderContext().getFunctions();
193 GLU_CHECK_CALL_ERROR(gl.bindFramebuffer(GL_FRAMEBUFFER, fbo),
198 gl.clearColor(0.0, 0.0, 0.0, 1.0);
199 GLU_CHECK_CALL_ERROR(gl.clear(GL_COLOR_BUFFER_BIT), gl.getError());
204 const GLsizei width = rnd.getInt(0, FRAMEBUFFER_SIZE);
205 const GLsizei height = rnd.getInt(0, FRAMEBUFFER_SIZE);
206 const GLint x = rnd.getInt(0, FRAMEBUFFER_SIZE - width);
207 const GLint y = rnd.getInt(0, FRAMEBUFFER_SIZE - height);
208 const GLfloat r1 = rnd.getFloat();
209 const GLfloat g1 = rnd.getFloat();
210 const GLfloat b1 = rnd.getFloat();
211 const GLfloat a1 = rnd.getFloat();
212 const GLfloat r2 = rnd.getFloat();
213 const GLfloat g2 = rnd.getFloat();
214 const GLfloat b2 = rnd.getFloat();
215 const GLfloat a2 = rnd.getFloat();
217 GLU_CHECK_CALL_ERROR(gl.clearColor(r1, g1, b1, a1), gl.getError());
218 GLU_CHECK_CALL_ERROR(gl.clear(GL_COLOR_BUFFER_BIT), gl.getError());
219 gl.scissor(x, y, width, height);
220 gl.enable(GL_SCISSOR_TEST);
221 gl.clearColor(r2, g2, b2, a2);
222 gl.clear(GL_COLOR_BUFFER_BIT);
223 gl.disable(GL_SCISSOR_TEST);
226 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
227 GLU_CHECK_ERROR(gl.getError());
230 void drawFbo (const Context& ctx, GLuint fbo, Surface& dst)
232 const RenderContext& renderCtx = ctx.getRenderContext();
233 const Functions& gl = renderCtx.getFunctions();
235 GLU_CHECK_CALL_ERROR(
236 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo),
239 dst.setSize(FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE);
240 glu::readPixels(renderCtx, 0, 0, dst.getAccess());
241 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels from framebuffer");
243 GLU_CHECK_CALL_ERROR(
244 gl.bindFramebuffer(GL_FRAMEBUFFER, 0),
248 GLuint getFboAttachment (const Functions& gl, GLuint fbo, GLenum requiredType)
250 GLint type = 0, name = 0;
251 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
252 GLU_CHECK_CALL_ERROR(
253 gl.getFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
254 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
257 GLU_CHECK_CALL_ERROR(
258 gl.getFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
259 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
262 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
263 GLU_CHECK_ERROR(gl.getError());
265 GLuint ret = GLenum(type) == requiredType ? name : 0;
269 void FboAttacher::initAttachment (GLuint seed, GLuint element)
271 Binder& binder = *getElementType().binder();
272 Framebuffer fbo(getRenderContext());
274 enableLogging(false);
276 binder.enableLogging(false);
277 binder.bind(element);
280 binder.enableLogging(true);
282 attach(element, *fbo);
283 setupFbo(getContext(), seed, *fbo);
284 detach(element, *fbo);
288 log() << TestLog::Message
289 << "// Drew to " << getElementType().getName() << " " << element
290 << " with seed " << seed << "."
291 << TestLog::EndMessage;
294 void FboInputAttacher::drawContainer (GLuint fbo, Surface& dst)
296 drawFbo(getContext(), fbo, dst);
297 log() << TestLog::Message
298 << "// Read pixels from framebuffer " << fbo << " to output image."
299 << TestLog::EndMessage;
302 void FboOutputAttacher::setupContainer (GLuint seed, GLuint fbo)
304 setupFbo(getContext(), seed, fbo);
305 log() << TestLog::Message
306 << "// Drew to framebuffer " << fbo << " with seed " << seed << "."
307 << TestLog::EndMessage;
310 void FboOutputAttacher::drawAttachment (GLuint element, Surface& dst)
312 Framebuffer fbo(getRenderContext());
313 m_attacher.enableLogging(false);
314 m_attacher.attach(element, *fbo);
315 drawFbo(getContext(), *fbo, dst);
316 m_attacher.detach(element, *fbo);
317 m_attacher.enableLogging(true);
318 log() << TestLog::Message
319 << "// Read pixels from " << m_attacher.getElementType().getName() << " " << element
320 << " to output image."
321 << TestLog::EndMessage;
322 GLU_CHECK_ERROR(gl().getError());
325 void TextureFboAttacher::attach (GLuint texture, GLuint fbo)
327 GLU_CHECK_CALL_ERROR(
328 glBindFramebuffer(GL_FRAMEBUFFER, fbo),
330 GLU_CHECK_CALL_ERROR(
331 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
332 GL_TEXTURE_2D, texture, 0),
334 GLU_CHECK_CALL_ERROR(
335 glBindFramebuffer(GL_FRAMEBUFFER, 0),
339 void TextureFboAttacher::detach (GLuint texture, GLuint fbo)
342 GLU_CHECK_CALL_ERROR(
343 glBindFramebuffer(GL_FRAMEBUFFER, fbo),
345 GLU_CHECK_CALL_ERROR(
346 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0),
348 GLU_CHECK_CALL_ERROR(
349 glBindFramebuffer(GL_FRAMEBUFFER, 0),
353 GLuint TextureFboAttacher::getAttachment (GLuint fbo)
355 return getFboAttachment(gl(), fbo, GL_TEXTURE);
358 void TextureFboAttacher::initStorage (void)
360 GLU_CHECK_CALL_ERROR(
361 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE, 0,
362 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, DE_NULL),
366 void RboFboAttacher::initStorage (void)
368 GLU_CHECK_CALL_ERROR(
369 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE),
373 void RboFboAttacher::attach (GLuint rbo, GLuint fbo)
375 GLU_CHECK_CALL_ERROR(
376 glBindFramebuffer(GL_FRAMEBUFFER, fbo),
378 GLU_CHECK_CALL_ERROR(
379 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo),
381 GLU_CHECK_CALL_ERROR(
382 glBindFramebuffer(GL_FRAMEBUFFER, 0),
386 void RboFboAttacher::detach (GLuint rbo, GLuint fbo)
389 GLU_CHECK_CALL_ERROR(
390 glBindFramebuffer(GL_FRAMEBUFFER, fbo),
392 GLU_CHECK_CALL_ERROR(
393 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0),
395 GLU_CHECK_CALL_ERROR(
396 glBindFramebuffer(GL_FRAMEBUFFER, 0),
400 GLuint RboFboAttacher::getAttachment (GLuint fbo)
402 return getFboAttachment(gl(), fbo, GL_RENDERBUFFER);
405 static const char* const s_fragmentShaderTemplate = GLSL100_SRC(
408 gl_FragColor = vec4(${RED}, ${GREEN}, ${BLUE}, 1.0);
412 void ShaderProgramAttacher::initAttachment (GLuint seed, GLuint shader)
415 using de::floatToString;
418 map<string, string> params;
419 const StringTemplate sourceTmpl (s_fragmentShaderTemplate);
421 insert(params, "RED", floatToString(rnd.getFloat(), 4));
422 insert(params, "GREEN", floatToString(rnd.getFloat(), 4));
423 insert(params, "BLUE", floatToString(rnd.getFloat(), 4));
426 const string source = sourceTmpl.specialize(params);
427 const char* const sourceStr = source.c_str();
429 GLU_CHECK_CALL_ERROR(glShaderSource(shader, 1, &sourceStr, DE_NULL), gl().getError());
430 GLU_CHECK_CALL_ERROR(glCompileShader(shader), gl().getError());
433 GLint compileStatus = 0;
434 gl().getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
435 TCU_CHECK_MSG(compileStatus != 0, sourceStr);
440 void ShaderProgramAttacher::attach (GLuint shader, GLuint program)
442 GLU_CHECK_CALL_ERROR(
443 glAttachShader(program, shader),
447 void ShaderProgramAttacher::detach (GLuint shader, GLuint program)
449 GLU_CHECK_CALL_ERROR(
450 glDetachShader(program, shader),
454 GLuint ShaderProgramAttacher::getAttachment (GLuint program)
456 GLuint shaders[2] = { 0, 0 };
457 const GLsizei shadersLen = DE_LENGTH_OF_ARRAY(shaders);
458 GLsizei numShaders = 0;
461 gl().getAttachedShaders(program, shadersLen, &numShaders, shaders);
463 // There should ever be at most one attached shader in normal use, but if
464 // something is wrong, the temporary vertex shader might not have been
465 // detached properly, so let's find the fragment shader explicitly.
466 for (int ndx = 0; ndx < de::min<GLsizei>(shadersLen, numShaders); ++ndx)
468 GLint shaderType = GL_NONE;
469 gl().getShaderiv(shaders[ndx], GL_SHADER_TYPE, &shaderType);
471 if (shaderType == GL_FRAGMENT_SHADER)
481 void setViewport (const RenderContext& renderCtx, const Rectangle& rect)
483 renderCtx.getFunctions().viewport(rect.x, rect.y, rect.width, rect.height);
486 void readRectangle (const RenderContext& renderCtx, const Rectangle& rect, Surface& dst)
488 dst.setSize(rect.width, rect.height);
489 glu::readPixels(renderCtx, rect.x, rect.y, dst.getAccess());
492 Rectangle randomViewport (const RenderContext& ctx, GLint maxWidth, GLint maxHeight,
495 const RenderTarget& target = ctx.getRenderTarget();
496 const GLint width = de::min(target.getWidth(), maxWidth);
497 const GLint xOff = rnd.getInt(0, target.getWidth() - width);
498 const GLint height = de::min(target.getHeight(), maxHeight);
499 const GLint yOff = rnd.getInt(0, target.getHeight() - height);
501 return Rectangle(xOff, yOff, width, height);
504 void ShaderProgramInputAttacher::drawContainer (GLuint program, Surface& dst)
506 static const float s_vertices[6] = { -1.0, 0.0, 1.0, 1.0, 0.0, -1.0 };
507 Random rnd (program);
508 CheckedShader vtxShader (getRenderContext(),
509 SHADERTYPE_VERTEX, s_vertexShaderSrc);
510 const Rectangle viewport = randomViewport(getRenderContext(),
511 VIEWPORT_SIZE, VIEWPORT_SIZE, rnd);
513 gl().attachShader(program, vtxShader.getShader());
514 gl().linkProgram(program);
517 GLint linkStatus = 0;
518 gl().getProgramiv(program, GL_LINK_STATUS, &linkStatus);
519 TCU_CHECK(linkStatus != 0);
522 log() << TestLog::Message
523 << "// Attached a temporary vertex shader and linked program " << program
524 << TestLog::EndMessage;
526 setViewport(getRenderContext(), viewport);
527 log() << TestLog::Message << "// Positioned viewport randomly" << TestLog::EndMessage;
529 glUseProgram(program);
531 GLint posLoc = gl().getAttribLocation(program, "pos");
532 TCU_CHECK(posLoc >= 0);
534 gl().enableVertexAttribArray(posLoc);
536 gl().clearColor(0, 0, 0, 1);
537 gl().clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
538 gl().vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, s_vertices);
539 gl().drawArrays(GL_TRIANGLES, 0, 3);
541 gl().disableVertexAttribArray(posLoc);
542 log () << TestLog::Message << "// Drew a fixed triangle" << TestLog::EndMessage;
546 readRectangle(getRenderContext(), viewport, dst);
547 log() << TestLog::Message << "// Copied viewport to output image" << TestLog::EndMessage;
549 gl().detachShader(program, vtxShader.getShader());
550 log() << TestLog::Message << "// Removed temporary vertex shader" << TestLog::EndMessage;
553 ES2Types::ES2Types (const Context& ctx)
555 , m_bufferBind (ctx, &CallLogWrapper::glBindBuffer,
556 GL_ARRAY_BUFFER, GL_ARRAY_BUFFER_BINDING)
557 , m_bufferType (ctx, "buffer", &CallLogWrapper::glGenBuffers,
558 &CallLogWrapper::glDeleteBuffers,
559 &CallLogWrapper::glIsBuffer, &m_bufferBind)
560 , m_textureBind (ctx, &CallLogWrapper::glBindTexture, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D)
561 , m_textureType (ctx, "texture", &CallLogWrapper::glGenTextures,
562 &CallLogWrapper::glDeleteTextures,
563 &CallLogWrapper::glIsTexture, &m_textureBind)
564 , m_rboBind (ctx, &CallLogWrapper::glBindRenderbuffer,
565 GL_RENDERBUFFER, GL_RENDERBUFFER_BINDING)
566 , m_rboType (ctx, "renderbuffer",
567 &CallLogWrapper::glGenRenderbuffers,
568 &CallLogWrapper::glDeleteRenderbuffers,
569 &CallLogWrapper::glIsRenderbuffer, &m_rboBind)
570 , m_fboBind (ctx, &CallLogWrapper::glBindFramebuffer,
571 GL_FRAMEBUFFER, GL_FRAMEBUFFER_BINDING)
572 , m_fboType (ctx, "framebuffer",
573 &CallLogWrapper::glGenFramebuffers,
574 &CallLogWrapper::glDeleteFramebuffers,
575 &CallLogWrapper::glIsFramebuffer, &m_fboBind)
577 , m_programType (ctx)
578 , m_texFboAtt (ctx, m_textureType, m_fboType)
579 , m_texFboInAtt (m_texFboAtt)
580 , m_texFboOutAtt(m_texFboAtt)
581 , m_rboFboAtt (ctx, m_rboType, m_fboType)
582 , m_rboFboInAtt (m_rboFboAtt)
583 , m_rboFboOutAtt(m_rboFboAtt)
584 , m_shaderAtt (ctx, m_shaderType, m_programType)
585 , m_shaderInAtt (m_shaderAtt)
587 Type* const types[] =
589 &m_bufferType, &m_textureType, &m_rboType, &m_fboType, &m_shaderType, &m_programType
591 m_types.insert(m_types.end(), DE_ARRAY_BEGIN(types), DE_ARRAY_END(types));
593 m_attachers.push_back(&m_texFboAtt);
594 m_attachers.push_back(&m_rboFboAtt);
595 m_attachers.push_back(&m_shaderAtt);
597 m_inAttachers.push_back(&m_texFboInAtt);
598 m_inAttachers.push_back(&m_rboFboInAtt);
599 m_inAttachers.push_back(&m_shaderInAtt);
601 m_outAttachers.push_back(&m_texFboOutAtt);
602 m_outAttachers.push_back(&m_rboFboOutAtt);
608 Name (Type& type) : m_type(type), m_name(type.gen()) {}
609 Name (Type& type, GLuint name) : m_type(type), m_name(name) {}
610 ~Name (void) { m_type.release(m_name); }
611 GLuint operator* (void) const { return m_name; }
618 class ResultCollector
621 ResultCollector (TestContext& testCtx);
622 bool check (bool cond, const char* msg);
623 void fail (const char* msg);
624 void warn (const char* msg);
625 ~ResultCollector (void);
628 void addResult (qpTestResult result, const char* msg);
630 TestContext& m_testCtx;
632 qpTestResult m_result;
633 const char* m_message;
636 ResultCollector::ResultCollector (TestContext& testCtx)
637 : m_testCtx (testCtx)
638 , m_log (testCtx.getLog())
639 , m_result (QP_TEST_RESULT_PASS)
644 bool ResultCollector::check (bool cond, const char* msg)
651 void ResultCollector::addResult (qpTestResult result, const char* msg)
653 m_log << TestLog::Message << "// Fail: " << msg << TestLog::EndMessage;
654 if (m_result == QP_TEST_RESULT_PASS)
661 if (result == QP_TEST_RESULT_FAIL)
663 m_message = "Multiple problems, see log for details";
667 void ResultCollector::fail (const char* msg)
669 addResult(QP_TEST_RESULT_FAIL, msg);
672 void ResultCollector::warn (const char* msg)
674 addResult(QP_TEST_RESULT_QUALITY_WARNING, msg);
677 ResultCollector::~ResultCollector (void)
679 m_testCtx.setTestResult(m_result, m_message);
682 class TestBase : public TestCase, protected CallLogWrapper
685 TestBase (const char* name,
686 const char* description,
689 // Copy ContextWrapper since MI (except for CallLogWrapper) is a no-no.
690 const Context& getContext (void) const { return m_ctx; }
691 const RenderContext& getRenderContext (void) const { return m_ctx.getRenderContext(); }
692 const Functions& gl (void) const { return m_ctx.gl(); }
693 TestLog& log (void) const { return m_ctx.log(); }
700 TestBase::TestBase (const char* name, const char* description, const Context& ctx)
701 : TestCase (ctx.getTestContext(), name, description)
702 , CallLogWrapper (ctx.gl(), ctx.log())
704 , m_rnd (deStringHash(name))
709 void TestBase::init (void)
711 m_rnd = Random(deStringHash(getName()));
714 class LifeTest : public TestBase
717 typedef void (LifeTest::*TestFunction) (void);
719 LifeTest (const char* name,
720 const char* description,
723 : TestBase (name, description, type.getContext())
727 IterateResult iterate (void);
730 void testDelete (void);
731 void testBind (void);
732 void testDeleteBound (void);
733 void testBindNoGen (void);
734 void testDeleteUsed (void);
737 Binder& binder (void) { return *m_type.binder(); }
743 IterateResult LifeTest::iterate (void)
749 void LifeTest::testGen (void)
751 ResultCollector errors (getTestContext());
754 if (m_type.genCreates())
755 errors.check(m_type.exists(*name), "Gen* should have created an object, but didn't");
757 errors.check(!m_type.exists(*name), "Gen* should not have created an object, but did");
760 void LifeTest::testDelete (void)
762 ResultCollector errors (getTestContext());
763 GLuint name = m_type.gen();
765 m_type.release(name);
766 errors.check(!m_type.exists(name), "Object still exists after deletion");
769 void LifeTest::testBind (void)
771 ResultCollector errors (getTestContext());
774 binder().bind(*name);
775 GLU_EXPECT_NO_ERROR(gl().getError(), "Bind failed");
776 errors.check(m_type.exists(*name), "Object does not exist after binding");
780 void LifeTest::testDeleteBound (void)
782 const GLuint id = m_type.gen();
783 ResultCollector errors (getTestContext());
788 if (m_type.nameLingers())
790 errors.check(gl().getError() == GL_NO_ERROR, "Deleting bound object failed");
791 errors.check(binder().getBinding() == id,
792 "Deleting bound object did not retain binding");
793 errors.check(m_type.exists(id),
794 "Deleting bound object made its name invalid");
795 errors.check(m_type.isDeleteFlagged(id),
796 "Deleting bound object did not flag the object for deletion");
801 errors.check(gl().getError() == GL_NO_ERROR, "Deleting bound object failed");
802 errors.check(binder().getBinding() == 0,
803 "Deleting bound object did not remove binding");
804 errors.check(!m_type.exists(id),
805 "Deleting bound object did not make its name invalid");
809 errors.check(binder().getBinding() == 0, "Unbinding didn't remove binding");
810 errors.check(!m_type.exists(id), "Name is still valid after deleting and unbinding");
813 void LifeTest::testBindNoGen (void)
815 ResultCollector errors (getTestContext());
816 const GLuint id = m_rnd.getUint32();
818 if (!errors.check(!m_type.exists(id), "Randomly chosen identifier already exists"))
821 Name name (m_type, id);
822 binder().bind(*name);
824 if (binder().genRequired())
826 errors.check(glGetError() == GL_INVALID_OPERATION,
827 "Did not fail when binding a name not generated by Gen* call");
828 errors.check(!m_type.exists(*name),
829 "Bind* created an object for a name not generated by a Gen* call");
833 errors.check(glGetError() == GL_NO_ERROR,
834 "Failed when binding a name not generated by Gen* call");
835 errors.check(m_type.exists(*name),
836 "Object was not created by the Bind* call");
840 void LifeTest::testDeleteUsed (void)
842 ResultCollector errors(getTestContext());
843 GLuint programId = 0;
846 CheckedShader vtxShader (getRenderContext(),
847 SHADERTYPE_VERTEX, s_vertexShaderSrc);
848 CheckedShader fragShader (getRenderContext(),
849 SHADERTYPE_FRAGMENT, s_fragmentShaderSrc);
850 CheckedProgram program (getRenderContext(),
851 vtxShader.getShader(), fragShader.getShader());
853 programId = program.getProgram();
855 log() << TestLog::Message << "// Created and linked program " << programId
856 << TestLog::EndMessage;
857 GLU_CHECK_CALL_ERROR(glUseProgram(programId), gl().getError());
859 log() << TestLog::Message << "// Deleted program " << programId
860 << TestLog::EndMessage;
862 TCU_CHECK(glIsProgram(programId));
864 GLint deleteFlagged = 0;
865 glGetProgramiv(programId, GL_DELETE_STATUS, &deleteFlagged);
866 errors.check(deleteFlagged != 0, "Program object was not flagged as deleted");
868 GLU_CHECK_CALL_ERROR(glUseProgram(0), gl().getError());
869 errors.check(!gl().isProgram(programId),
870 "Deleted program name still valid after being made non-current");
873 class AttachmentTest : public TestBase
876 typedef void (AttachmentTest::*TestFunction) (void);
877 AttachmentTest (const char* name,
878 const char* description,
881 : TestBase (name, description, attacher.getContext())
882 , m_attacher (attacher)
884 IterateResult iterate (void);
886 void testDeletedNames (void);
887 void testDeletedBinding (void);
888 void testDeletedReattach (void);
891 Attacher& m_attacher;
892 const TestFunction m_test;
895 IterateResult AttachmentTest::iterate (void)
901 GLuint getAttachment (Attacher& attacher, GLuint container)
903 const GLuint queriedAttachment = attacher.getAttachment(container);
904 attacher.log() << TestLog::Message
905 << "// Result of query for " << attacher.getElementType().getName()
906 << " attached to " << attacher.getContainerType().getName() << " "
907 << container << ": " << queriedAttachment << "."
908 << TestLog::EndMessage;
909 return queriedAttachment;
912 void AttachmentTest::testDeletedNames (void)
914 Type& elemType = m_attacher.getElementType();
915 Type& containerType = m_attacher.getContainerType();
916 Name container (containerType);
917 ResultCollector errors (getTestContext());
918 GLuint elementId = 0;
921 Name element(elemType);
922 elementId = *element;
923 m_attacher.initAttachment(0, *element);
924 m_attacher.attach(*element, *container);
925 errors.check(getAttachment(m_attacher, *container) == elementId,
926 "Attachment name not returned by query even before deletion.");
929 // "Such a container or other context may continue using the object, and
930 // may still contain state identifying its name as being currently bound"
932 // We here interpret "may" to mean that whenever the container has a
933 // deleted object attached to it, a query will return that object's former
935 errors.check(getAttachment(m_attacher, *container) == elementId,
936 "Attachment name not returned by query after attachment was deleted.");
938 if (elemType.nameLingers())
939 errors.check(elemType.exists(elementId),
940 "Attached object name no longer valid after deletion.");
942 errors.check(!elemType.exists(elementId),
943 "Attached object name still valid after deletion.");
945 m_attacher.detach(elementId, *container);
946 errors.check(getAttachment(m_attacher, *container) == 0,
947 "Attachment name returned by query even after detachment.");
948 errors.check(!elemType.exists(elementId),
949 "Deleted attached object name still usable after detachment.");
952 class InputAttachmentTest : public TestBase
955 InputAttachmentTest (const char* name,
956 const char* description,
957 InputAttacher& inputAttacher)
958 : TestBase (name, description, inputAttacher.getContext())
959 , m_inputAttacher (inputAttacher) {}
961 IterateResult iterate (void);
964 InputAttacher& m_inputAttacher;
967 GLuint replaceName (Type& type, GLuint oldName, TestLog& log)
969 const Binder* const binder = type.binder();
970 const bool genRequired = binder == DE_NULL || binder->genRequired();
975 log << TestLog::Message
976 << "// Type does not require Gen* for binding, reusing old id " << oldName << "."
977 << TestLog::EndMessage;
982 IterateResult InputAttachmentTest::iterate (void)
984 Attacher& attacher = m_inputAttacher.getAttacher();
985 Type& containerType = attacher.getContainerType();
986 Type& elementType = attacher.getElementType();
987 Name container (containerType);
988 GLuint elementId = 0;
989 const GLuint refSeed = m_rnd.getUint32();
990 const GLuint newSeed = m_rnd.getUint32();
991 ResultCollector errors (getTestContext());
993 Surface refSurface; // Surface from drawing with refSeed-seeded attachment
994 Surface delSurface; // Surface from drawing with deleted refSeed attachment
995 Surface newSurface; // Surface from drawing with newSeed-seeded attachment
997 log() << TestLog::Message
998 << "Testing if writing to a newly created object modifies a deleted attachment"
999 << TestLog::EndMessage;
1002 ScopedLogSection section (log(),
1003 "Write to original", "Writing to an original attachment");
1004 const Name element (elementType);
1006 elementId = *element;
1007 attacher.initAttachment(refSeed, elementId);
1008 attacher.attach(elementId, *container);
1009 m_inputAttacher.drawContainer(*container, refSurface);
1010 // element gets deleted here
1011 log() << TestLog::Message << "// Deleting attachment";
1014 ScopedLogSection section (log(), "Write to new",
1015 "Writing to a new attachment after deleting the original");
1016 const GLuint newId = replaceName(elementType, elementId, log());
1017 const Name newElement (elementType, newId);
1019 attacher.initAttachment(newSeed, newId);
1021 m_inputAttacher.drawContainer(*container, delSurface);
1022 attacher.detach(elementId, *container);
1024 attacher.attach(newId, *container);
1025 m_inputAttacher.drawContainer(*container, newSurface);
1026 attacher.detach(newId, *container);
1029 const bool surfacesMatch = tcu::pixelThresholdCompare(
1030 log(), "Reading from deleted",
1031 "Comparison result from reading from a container with a deleted attachment "
1032 "before and after writing to a fresh object.",
1033 refSurface, delSurface, RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1037 "Writing to a fresh object modified the container with a deleted attachment.");
1040 log() << TestLog::Image("New attachment",
1041 "Container state after attached to the fresh object",
1048 class OutputAttachmentTest : public TestBase
1051 OutputAttachmentTest (const char* name,
1052 const char* description,
1053 OutputAttacher& outputAttacher)
1054 : TestBase (name, description,
1055 outputAttacher.getContext())
1056 , m_outputAttacher (outputAttacher) {}
1057 IterateResult iterate (void);
1060 OutputAttacher& m_outputAttacher;
1063 IterateResult OutputAttachmentTest::iterate (void)
1065 Attacher& attacher = m_outputAttacher.getAttacher();
1066 Type& containerType = attacher.getContainerType();
1067 Type& elementType = attacher.getElementType();
1068 Name container (containerType);
1069 GLuint elementId = 0;
1070 const GLuint refSeed = m_rnd.getUint32();
1071 const GLuint newSeed = m_rnd.getUint32();
1072 ResultCollector errors (getTestContext());
1073 Surface refSurface; // Surface drawn from attachment to refSeed container
1074 Surface newSurface; // Surface drawn from attachment to newSeed container
1075 Surface delSurface; // Like newSurface, after writing to a deleted attachment
1077 log() << TestLog::Message
1078 << "Testing if writing to a container with a deleted attachment "
1079 << "modifies a newly created object"
1080 << TestLog::EndMessage;
1083 ScopedLogSection section (log(), "Write to existing",
1084 "Writing to a container with an existing attachment");
1085 const Name element (elementType);
1087 elementId = *element;
1088 attacher.initAttachment(0, elementId);
1089 attacher.attach(elementId, *container);
1091 // For reference purposes, make note of what refSeed looks like.
1092 m_outputAttacher.setupContainer(refSeed, *container);
1093 m_outputAttacher.drawAttachment(elementId, refSurface);
1096 ScopedLogSection section (log(), "Write to deleted",
1097 "Writing to a container after deletion of attachment");
1098 const GLuint newId = replaceName(elementType, elementId, log());
1099 const Name newElement (elementType, newId);
1101 log() << TestLog::Message
1102 << "Creating a new object " << newId
1103 << TestLog::EndMessage;
1105 log() << TestLog::Message
1106 << "Recording state of new object before writing to container"
1107 << TestLog::EndMessage;
1108 attacher.initAttachment(newSeed, newId);
1109 m_outputAttacher.drawAttachment(newId, newSurface);
1111 log() << TestLog::Message
1112 << "Writing to container"
1113 << TestLog::EndMessage;
1115 // Now re-write refSeed to the container.
1116 m_outputAttacher.setupContainer(refSeed, *container);
1117 // Does it affect the newly created attachment object?
1118 m_outputAttacher.drawAttachment(newId, delSurface);
1120 attacher.detach(elementId, *container);
1122 const bool surfacesMatch = tcu::pixelThresholdCompare(
1123 log(), "Writing to deleted",
1124 "Comparison result from reading from a fresh object before and after "
1125 "writing to a container with a deleted attachment",
1126 newSurface, delSurface, RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1128 errors.check(surfacesMatch,
1129 "Writing to container with deleted attachment modified a new object.");
1132 log() << TestLog::Image(
1133 "Original attachment",
1134 "Result of container modification on original attachment before deletion.",
1142 LifeTest::TestFunction func;
1146 MovePtr<TestCaseGroup> createLifeTestGroup (TestContext& testCtx,
1147 const LifeTestSpec& spec,
1148 const vector<Type*>& types)
1150 MovePtr<TestCaseGroup> group(new TestCaseGroup(testCtx, spec.name, spec.name));
1152 for (vector<Type*>::const_iterator it = types.begin(); it != types.end(); ++it)
1155 const char* name = type.getName();
1156 if (!spec.needBind || type.binder() != DE_NULL)
1157 group->addChild(new LifeTest(name, name, type, spec.func));
1163 static const LifeTestSpec s_lifeTests[] =
1165 { "gen", &LifeTest::testGen, false },
1166 { "delete", &LifeTest::testDelete, false },
1167 { "bind", &LifeTest::testBind, true },
1168 { "delete_bound", &LifeTest::testDeleteBound, true },
1169 { "bind_no_gen", &LifeTest::testBindNoGen, true },
1172 string attacherName (Attacher& attacher)
1175 os << attacher.getElementType().getName() << "_" << attacher.getContainerType().getName();
1179 void addTestCases (TestCaseGroup& group, Types& types)
1181 TestContext& testCtx = types.getTestContext();
1183 for (const LifeTestSpec* it = DE_ARRAY_BEGIN(s_lifeTests);
1184 it != DE_ARRAY_END(s_lifeTests); ++it)
1185 group.addChild(createLifeTestGroup(testCtx, *it, types.getTypes()).release());
1188 TestCaseGroup* const delUsedGroup =
1189 new TestCaseGroup(testCtx, "delete_used", "Delete current program");
1190 group.addChild(delUsedGroup);
1192 delUsedGroup->addChild(
1193 new LifeTest("program", "program", types.getProgramType(),
1194 &LifeTest::testDeleteUsed));
1198 TestCaseGroup* const attGroup = new TestCaseGroup(
1199 testCtx, "attach", "Attachment tests");
1200 group.addChild(attGroup);
1203 TestCaseGroup* const nameGroup = new TestCaseGroup(
1204 testCtx, "deleted_name", "Name of deleted attachment");
1205 attGroup->addChild(nameGroup);
1207 const vector<Attacher*>& atts = types.getAttachers();
1208 for (vector<Attacher*>::const_iterator it = atts.begin(); it != atts.end(); ++it)
1210 const string name = attacherName(**it);
1211 nameGroup->addChild(new AttachmentTest(name.c_str(), name.c_str(), **it,
1212 &AttachmentTest::testDeletedNames));
1216 TestCaseGroup* inputGroup = new TestCaseGroup(
1217 testCtx, "deleted_input", "Input from deleted attachment");
1218 attGroup->addChild(inputGroup);
1220 const vector<InputAttacher*>& inAtts = types.getInputAttachers();
1221 for (vector<InputAttacher*>::const_iterator it = inAtts.begin();
1222 it != inAtts.end(); ++it)
1224 const string name = attacherName((*it)->getAttacher());
1225 inputGroup->addChild(new InputAttachmentTest(name.c_str(), name.c_str(), **it));
1229 TestCaseGroup* outputGroup = new TestCaseGroup(
1230 testCtx, "deleted_output", "Output to deleted attachment");
1231 attGroup->addChild(outputGroup);
1233 const vector<OutputAttacher*>& outAtts = types.getOutputAttachers();
1234 for (vector<OutputAttacher*>::const_iterator it = outAtts.begin();
1235 it != outAtts.end(); ++it)
1237 string name = attacherName((*it)->getAttacher());
1238 outputGroup->addChild(new OutputAttachmentTest(name.c_str(), name.c_str(),