Merge "Fix extension support checks in negative api tests" into nougat-cts-dev am...
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsLifetimeTests.cpp
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