Merge "Fix extension support checks in negative api tests" into nougat-cts-dev am...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fLifetimeTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 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 Object lifetime tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fLifetimeTests.hpp"
25
26 #include "deRandom.hpp"
27 #include "deUniquePtr.hpp"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuSurface.hpp"
30 #include "gluDrawUtil.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "glsLifetimeTests.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37
38 #include <vector>
39
40 namespace deqp
41 {
42 namespace gles3
43 {
44 namespace Functional
45 {
46 namespace
47 {
48
49 using std::vector;
50 using de::MovePtr;
51 using de::Random;
52 using tcu::RenderTarget;
53 using tcu::Surface;
54 using tcu::TestContext;
55 using tcu::TestLog;
56 using glu::CallLogWrapper;
57 using glu::RenderContext;
58 using glu::ProgramSources;
59 using glu::VertexArray;
60 using glu::Buffer;
61 namespace lt = gls::LifetimeTests;
62 using namespace lt;
63 using namespace glw;
64 typedef TestCase::IterateResult IterateResult;
65
66 enum { VIEWPORT_SIZE = 128 };
67
68 class ScaleProgram : public glu::ShaderProgram
69 {
70 public:
71                                                         ScaleProgram    (lt::Context& ctx);
72         void                                    draw                    (GLuint vao, GLfloat scale, bool tf, Surface* dst);
73         void                                    setPos                  (GLuint buffer, GLuint vao);
74
75 private:
76         ProgramSources                  getSources              (void);
77
78         const RenderContext&    m_renderCtx;
79         GLint                                   m_scaleLoc;
80         GLint                                   m_posLoc;
81 };
82
83 enum { NUM_COMPONENTS = 4, NUM_VERTICES = 3 };
84
85 ScaleProgram::ScaleProgram (lt::Context& ctx)
86         : glu::ShaderProgram    (ctx.getRenderContext(), getSources())
87         , m_renderCtx                   (ctx.getRenderContext())
88 {
89         const Functions& gl = m_renderCtx.getFunctions();
90         TCU_CHECK(isOk());
91         m_scaleLoc = gl.getUniformLocation(getProgram(), "scale");
92         m_posLoc = gl.getAttribLocation(getProgram(), "pos");
93 }
94
95 #define GLSL(VERSION, BODY) ("#version " #VERSION "\n" #BODY "\n")
96
97 static const char* const s_vertexShaderSrc = GLSL(
98         100,
99         attribute vec4 pos;
100         uniform float scale;
101         void main ()
102         {
103                 gl_Position = vec4(scale * pos.xy, pos.zw);
104         }
105         );
106
107 static const char* const s_fragmentShaderSrc = GLSL(
108         100,
109         void main ()
110         {
111                 gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
112         }
113         );
114
115 ProgramSources ScaleProgram::getSources (void)
116 {
117         using namespace glu;
118         ProgramSources sources;
119         sources << VertexSource(s_vertexShaderSrc)
120                         << FragmentSource(s_fragmentShaderSrc)
121                         << TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
122                         << TransformFeedbackVarying("gl_Position");
123         return sources;
124 }
125
126 void ScaleProgram::draw (GLuint vao, GLfloat scale, bool tf, Surface* dst)
127 {
128         const Functions&        gl                      = m_renderCtx.getFunctions();
129         de::Random                      rnd                     (vao);
130         Rectangle                       viewport        = randomViewport(m_renderCtx,
131                                                                                                          VIEWPORT_SIZE, VIEWPORT_SIZE, rnd);
132         setViewport(m_renderCtx, viewport);
133         gl.clearColor(0, 0, 0, 1);
134         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135
136         gl.bindVertexArray(vao);
137         gl.enableVertexAttribArray(m_posLoc);
138         GLU_CHECK_CALL_ERROR(gl.useProgram(getProgram()),
139                                                  gl.getError());
140
141         gl.uniform1f(m_scaleLoc, scale);
142
143         if (tf)
144                 gl.beginTransformFeedback(GL_TRIANGLES);
145         GLU_CHECK_CALL_ERROR(gl.drawArrays(GL_TRIANGLES, 0, 3), gl.getError());
146         if (tf)
147                 gl.endTransformFeedback();
148
149         if (dst != DE_NULL)
150                 readRectangle(m_renderCtx, viewport, *dst);
151
152         gl.bindVertexArray(0);
153 }
154
155 void ScaleProgram::setPos (GLuint buffer, GLuint vao)
156 {
157         const Functions& gl = m_renderCtx.getFunctions();
158
159         gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
160         gl.bindVertexArray(vao);
161         GLU_CHECK_CALL_ERROR(
162                 gl.vertexAttribPointer(m_posLoc, NUM_COMPONENTS, GL_FLOAT, false, 0, DE_NULL),
163                 gl.getError());
164         gl.bindVertexArray(0);
165         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
166         GLU_CHECK_ERROR(gl.getError());
167 }
168
169 class VertexArrayBinder : public SimpleBinder
170 {
171 public:
172                                                 VertexArrayBinder       (lt::Context& ctx)
173                                                         : SimpleBinder  (ctx, 0, GL_NONE, GL_VERTEX_ARRAY_BINDING, true) {}
174         void                            bind                    (GLuint name) { glBindVertexArray(name); }
175 };
176
177 class SamplerBinder : public Binder
178 {
179 public:
180                                                 SamplerBinder   (lt::Context& ctx) : Binder(ctx) {}
181         void                            bind                    (GLuint name) { glBindSampler(0, name); }
182         GLuint                          getBinding              (void)
183         {
184                 GLint arr[32] = {};
185                 glGetIntegerv(GL_SAMPLER_BINDING, arr);
186                 log() << TestLog::Message << "// First output integer: " << arr[0]
187                           << TestLog::EndMessage;
188                 return arr[0];
189         }
190         bool                            genRequired             (void) const { return true; }
191 };
192
193 class QueryBinder : public Binder
194 {
195 public:
196                                                 QueryBinder             (lt::Context& ctx) : Binder(ctx) {}
197         void                            bind                    (GLuint name)
198         {
199                 if (name != 0)
200                         glBeginQuery(GL_ANY_SAMPLES_PASSED, name);
201                 else
202                         glEndQuery(GL_ANY_SAMPLES_PASSED);
203         }
204         GLuint                          getBinding              (void) { return 0; }
205 };
206
207 class BufferVAOAttacher : public Attacher
208 {
209 public:
210                                                 BufferVAOAttacher       (lt::Context& ctx, Type& elementType,
211                                                                                          Type& varrType, ScaleProgram& program)
212                                                         : Attacher              (ctx, elementType, varrType)
213                                                         , m_program             (program) {}
214         void                            initAttachment          (GLuint seed, GLuint element);
215         void                            attach                          (GLuint element, GLuint container);
216         void                            detach                          (GLuint element, GLuint container);
217         bool                            canAttachDeleted        (void) const { return false; }
218         ScaleProgram&           getProgram                      (void) { return m_program; }
219         GLuint                          getAttachment           (GLuint container);
220
221 private:
222         ScaleProgram&           m_program;
223 };
224
225 static const GLfloat s_varrData[NUM_VERTICES * NUM_COMPONENTS] =
226 {
227         -1.0,  0.0, 0.0, 1.0,
228          1.0,  1.0, 0.0, 1.0,
229          0.0, -1.0, 0.0, 1.0
230 };
231
232 void initBuffer (const Functions& gl, GLuint seed, GLenum usage, GLuint buffer)
233 {
234         gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
235         if (seed == 0)
236                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(s_varrData), s_varrData, usage);
237         else
238         {
239                 Random  rnd     (seed);
240                 GLfloat data[DE_LENGTH_OF_ARRAY(s_varrData)];
241
242                 for (int ndx = 0; ndx < NUM_VERTICES; ndx++)
243                 {
244                         GLfloat* vertex = &data[ndx * NUM_COMPONENTS];
245                         vertex[0] = 2.0f * (rnd.getFloat() - 0.5f);
246                         vertex[1] = 2.0f * (rnd.getFloat() - 0.5f);
247                         DE_STATIC_ASSERT(NUM_COMPONENTS == 4);
248                         vertex[2] = 0.0f;
249                         vertex[3] = 1.0f;
250                 }
251                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, usage);
252         }
253         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
254         GLU_CHECK_ERROR(gl.getError());
255 }
256
257 void BufferVAOAttacher::initAttachment (GLuint seed, GLuint buffer)
258 {
259         initBuffer(gl(), seed, GL_STATIC_DRAW, buffer);
260         log() << TestLog::Message << "// Initialized buffer " << buffer << " from seed " << seed
261                   << TestLog::EndMessage;
262 }
263
264 void BufferVAOAttacher::attach (GLuint buffer, GLuint vao)
265 {
266         m_program.setPos(buffer, vao);
267         log() << TestLog::Message
268                   << "// Set the `pos` attribute in VAO " << vao << " to buffer " << buffer
269                   << TestLog::EndMessage;
270 }
271
272 void BufferVAOAttacher::detach (GLuint buffer, GLuint varr)
273 {
274         DE_UNREF(buffer);
275         attach(0, varr);
276 }
277
278 GLuint BufferVAOAttacher::getAttachment (GLuint varr)
279 {
280         GLint name = 0;
281         gl().bindVertexArray(varr);
282         gl().getVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &name);
283         gl().bindVertexArray(0);
284         GLU_CHECK_ERROR(gl().getError());
285         return GLuint(name);
286 }
287
288 class BufferVAOInputAttacher : public InputAttacher
289 {
290 public:
291                                                 BufferVAOInputAttacher  (BufferVAOAttacher& attacher)
292                                                         : InputAttacher         (attacher)
293                                                         , m_program                     (attacher.getProgram()) {}
294         void                            drawContainer                   (GLuint container, Surface& dst);
295
296 private:
297         ScaleProgram&           m_program;
298 };
299
300 void BufferVAOInputAttacher::drawContainer (GLuint vao, Surface& dst)
301 {
302         m_program.draw(vao, 1.0, false, &dst);
303         log() << TestLog::Message << "// Drew an output image with VAO " << vao
304                   << TestLog::EndMessage;
305 };
306
307 class BufferTfAttacher : public Attacher
308 {
309 public:
310                                 BufferTfAttacher        (lt::Context& ctx, Type& bufferType, Type& tfType)
311                                         : Attacher              (ctx, bufferType, tfType) {}
312         void            initAttachment          (GLuint seed, GLuint element);
313         void            attach                          (GLuint buffer, GLuint tf);
314         void            detach                          (GLuint buffer, GLuint tf);
315         bool            canAttachDeleted        (void) const { return false; }
316         GLuint          getAttachment           (GLuint tf);
317 };
318
319 void BufferTfAttacher::initAttachment (GLuint seed, GLuint buffer)
320 {
321         initBuffer(gl(), seed, GL_DYNAMIC_READ, buffer);
322         log() << TestLog::Message << "// Initialized buffer " << buffer << " from seed " << seed
323                   << TestLog::EndMessage;
324 }
325
326 void BufferTfAttacher::attach (GLuint buffer, GLuint tf)
327 {
328         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
329         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
330         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
331         GLU_CHECK_ERROR(gl().getError());
332 }
333
334 void BufferTfAttacher::detach (GLuint buffer, GLuint tf)
335 {
336         DE_UNREF(buffer);
337         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
338         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
339         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
340         GLU_CHECK_ERROR(gl().getError());
341 }
342
343 GLuint BufferTfAttacher::getAttachment (GLuint tf)
344 {
345         GLint ret = 0;
346         gl().bindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
347         gl().getIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &ret);
348         gl().bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
349         GLU_CHECK_ERROR(gl().getError());
350         return GLuint(ret);
351 }
352
353 class BufferTfOutputAttacher : public OutputAttacher
354 {
355 public:
356                                 BufferTfOutputAttacher  (BufferTfAttacher&      attacher, ScaleProgram& program)
357                                         : OutputAttacher        (attacher)
358                                         , m_program                     (program) {}
359         void            setupContainer          (GLuint seed, GLuint container);
360         void            drawAttachment          (GLuint attachment, Surface& dst);
361
362 private:
363         ScaleProgram&   m_program;
364 };
365
366 void BufferTfOutputAttacher::drawAttachment (GLuint buffer, Surface& dst)
367 {
368         VertexArray vao(getRenderContext());
369
370         m_program.setPos(buffer, *vao);
371         m_program.draw(*vao, 1.0, false, &dst);
372         log() << TestLog::Message
373                   << "// Drew output image with vertices from buffer " << buffer
374                   << TestLog::EndMessage;
375         GLU_CHECK_ERROR(gl().getError());
376 }
377
378 void BufferTfOutputAttacher::setupContainer (GLuint seed, GLuint tf)
379 {
380         Buffer          posBuf  (getRenderContext());
381         VertexArray     vao             (getRenderContext());
382
383         initBuffer(gl(), seed, GL_STATIC_DRAW, *posBuf);
384         m_program.setPos(*posBuf, *vao);
385
386         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
387         m_program.draw(*vao, -1.0, true, DE_NULL);
388         log() << TestLog::Message
389                   << "// Drew an image with seed " << seed << " with transform feedback to " << tf
390                   << TestLog::EndMessage;
391         glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
392         GLU_CHECK_ERROR(gl().getError());
393 }
394
395 class ES3Types : public ES2Types
396 {
397 public:
398                                                         ES3Types                (lt::Context& ctx);
399 private:
400         ScaleProgram                    m_program;
401         QueryBinder                             m_queryBind;
402         SimpleType                              m_queryType;
403         SimpleBinder                    m_tfBind;
404         SimpleType                              m_tfType;
405         VertexArrayBinder               m_varrBind;
406         SimpleType                              m_varrType;
407         SamplerBinder                   m_samplerBind;
408         SimpleType                              m_samplerType;
409         BufferVAOAttacher               m_bufVarrAtt;
410         BufferVAOInputAttacher  m_bufVarrInAtt;
411         BufferTfAttacher                m_bufTfAtt;
412         BufferTfOutputAttacher  m_bufTfOutAtt;
413 };
414
415 ES3Types::ES3Types (lt::Context& ctx)
416         : ES2Types              (ctx)
417         , m_program             (ctx)
418         , m_queryBind   (ctx)
419         , m_queryType   (ctx, "query", &CallLogWrapper::glGenQueries,
420                                          &CallLogWrapper::glDeleteQueries,
421                                          &CallLogWrapper::glIsQuery, &m_queryBind)
422         , m_tfBind              (ctx, &CallLogWrapper::glBindTransformFeedback, GL_TRANSFORM_FEEDBACK,
423                                          GL_TRANSFORM_FEEDBACK_BINDING, true)
424         , m_tfType              (ctx, "transform_feedback", &CallLogWrapper::glGenTransformFeedbacks,
425                                          &CallLogWrapper::glDeleteTransformFeedbacks,
426                                          &CallLogWrapper::glIsTransformFeedback, &m_tfBind)
427         , m_varrBind    (ctx)
428         , m_varrType    (ctx, "vertex_array", &CallLogWrapper::glGenVertexArrays,
429                                          &CallLogWrapper::glDeleteVertexArrays,
430                                          &CallLogWrapper::glIsVertexArray, &m_varrBind)
431         , m_samplerBind (ctx)
432         , m_samplerType (ctx, "sampler", &CallLogWrapper::glGenSamplers,
433                                          &CallLogWrapper::glDeleteSamplers,
434                                          &CallLogWrapper::glIsSampler, &m_samplerBind, true)
435         , m_bufVarrAtt  (ctx, m_bufferType, m_varrType, m_program)
436         , m_bufVarrInAtt(m_bufVarrAtt)
437         , m_bufTfAtt    (ctx, m_bufferType, m_tfType)
438         , m_bufTfOutAtt (m_bufTfAtt, m_program)
439 {
440         Type* types[] = { &m_queryType, &m_tfType, &m_varrType, &m_samplerType };
441         m_types.insert(m_types.end(), DE_ARRAY_BEGIN(types), DE_ARRAY_END(types));
442
443         m_attachers.push_back(&m_bufVarrAtt);
444         m_attachers.push_back(&m_bufTfAtt);
445
446         m_inAttachers.push_back(&m_bufVarrInAtt);
447         m_outAttachers.push_back(&m_bufTfOutAtt);
448 }
449
450 class TfDeleteActiveTest : public TestCase, private CallLogWrapper
451 {
452         public:
453                                                 TfDeleteActiveTest      (gles3::Context& context,
454                                                                                          const char* name, const char* description);
455         IterateResult           iterate                         (void);
456 };
457
458 TfDeleteActiveTest::TfDeleteActiveTest (gles3::Context& context,
459                                                                                 const char* name, const char* description)
460         : TestCase                      (context, name, description)
461         , CallLogWrapper        (context.getRenderContext().getFunctions(),
462                                                  context.getTestContext().getLog())
463 {
464         enableLogging(true);
465 }
466
467 class ScopedTransformFeedbackFeedback
468 {
469 public:
470                                                         ScopedTransformFeedbackFeedback         (glu::CallLogWrapper& gl, GLenum type);
471                                                         ~ScopedTransformFeedbackFeedback        (void);
472
473 private:
474         glu::CallLogWrapper&    m_gl;
475 };
476
477 ScopedTransformFeedbackFeedback::ScopedTransformFeedbackFeedback (glu::CallLogWrapper& gl, GLenum type)
478         : m_gl(gl)
479 {
480         m_gl.glBeginTransformFeedback(type);
481         GLU_EXPECT_NO_ERROR(m_gl.glGetError(), "glBeginTransformFeedback");
482 }
483
484 ScopedTransformFeedbackFeedback::~ScopedTransformFeedbackFeedback (void)
485 {
486         m_gl.glEndTransformFeedback();
487 }
488
489 IterateResult TfDeleteActiveTest::iterate (void)
490 {
491         static const char* const s_xfbVertexSource =    "#version 300 es\n"
492                                                                                                         "void main ()\n"
493                                                                                                         "{\n"
494                                                                                                         "       gl_Position = vec4(float(gl_VertexID) / 2.0, float(gl_VertexID % 2) / 2.0, 0.0, 1.0);\n"
495                                                                                                         "}\n";
496         static const char* const s_xfbFragmentSource =  "#version 300 es\n"
497                                                                                                         "layout(location=0) out mediump vec4 dEQP_FragColor;\n"
498                                                                                                         "void main ()\n"
499                                                                                                         "{\n"
500                                                                                                         "       dEQP_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
501                                                                                                         "}\n";
502
503         glu::Buffer                     buf                     (m_context.getRenderContext());
504         GLuint                          tf                      = 0;
505         glu::ShaderProgram      program         (m_context.getRenderContext(),
506                                                                          glu::ProgramSources()
507                                                                                 << glu::VertexSource(s_xfbVertexSource)
508                                                                                 << glu::FragmentSource(s_xfbFragmentSource)
509                                                                                 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
510                                                                                 << glu::TransformFeedbackVarying("gl_Position"));
511
512         if (!program.isOk())
513         {
514                 m_testCtx.getLog() << program;
515                 throw tcu::TestError("failed to build program");
516         }
517
518         try
519         {
520                 GLU_CHECK_CALL(glUseProgram(program.getProgram()));
521                 GLU_CHECK_CALL(glGenTransformFeedbacks(1, &tf));
522                 GLU_CHECK_CALL(glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf));
523                 GLU_CHECK_CALL(glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *buf));
524                 GLU_CHECK_CALL(glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(glw::GLfloat[4]), DE_NULL, GL_DYNAMIC_COPY));
525
526                 {
527                         ScopedTransformFeedbackFeedback xfb(static_cast<glu::CallLogWrapper&>(*this), GL_TRIANGLES);
528
529                         glDeleteTransformFeedbacks(1, &tf);
530                         {
531                                 GLenum err = glGetError();
532                                 if (err != GL_INVALID_OPERATION)
533                                         getTestContext().setTestResult(
534                                                 QP_TEST_RESULT_FAIL,
535                                                 "Deleting active transform feedback did not produce GL_INVALID_OPERATION");
536                                 else
537                                         getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
538                         }
539                 }
540                 GLU_CHECK(); // ScopedTransformFeedbackFeedback::dtor might modify error state
541
542                 GLU_CHECK_CALL(glDeleteTransformFeedbacks(1, &tf));
543         }
544         catch (const glu::Error&)
545         {
546                 glDeleteTransformFeedbacks(1, &tf);
547                 throw;
548         }
549
550         return STOP;
551 }
552
553 class TestGroup : public TestCaseGroup
554 {
555 public:
556                                                         TestGroup               (gles3::Context& context)
557                                                                 : TestCaseGroup (context, "lifetime", "Object lifetime tests")
558                                                         {}
559         void                                    init                    (void);
560 private:
561         MovePtr<Types>                  m_types;
562 };
563
564 void TestGroup::init (void)
565 {
566         gles3::Context& ctx             = getContext();
567         lt::Context             ltCtx   (ctx.getRenderContext(), ctx.getTestContext());
568
569         m_types = MovePtr<Types>(new ES3Types(ltCtx));
570
571         addTestCases(*this, *m_types);
572
573         TestCaseGroup* deleteActiveGroup =
574                 new TestCaseGroup(ctx, "delete_active", "Delete active object");
575         addChild(deleteActiveGroup);
576         deleteActiveGroup->addChild(
577                 new TfDeleteActiveTest(ctx, "transform_feedback", "Transform Feedback"));
578 }
579
580 } // anonymous
581
582 TestCaseGroup* createLifetimeTests (Context& context)
583 {
584         return new TestGroup(context);
585 }
586
587 } // Functional
588 } // gles3
589 } // deqp