ac8e25175970ed378abd9b4c1b1f67ae4ab925c5
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / glcRobustnessTests.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
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 glcRobustnessTests.cpp
21  * \brief Conformance tests for the Robustness feature functionality.
22  */ /*-------------------------------------------------------------------*/
23
24 #include "glcRobustnessTests.hpp"
25 #include "deSharedPtr.hpp"
26 #include "glcRobustBufferAccessBehaviorTests.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluPlatform.hpp"
29 #include "gluRenderContext.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "tcuTestLog.hpp"
34 #include <cstring>
35
36 using namespace glw;
37 using namespace deqp::RobustBufferAccessBehavior;
38
39 namespace glcts
40 {
41
42 namespace ResetNotificationStrategy
43 {
44
45 class RobustnessBase : public tcu::TestCase
46 {
47 public:
48         RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType);
49
50         glu::RenderContext* createRobustContext(glu::ResetNotificationStrategy reset);
51
52 private:
53         glu::ApiType m_ApiType;
54 };
55
56 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description,
57                                                            glu::ApiType apiType)
58         : tcu::TestCase(testCtx, name, description), m_ApiType(apiType)
59 {
60 }
61
62 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
63 {
64         /* Create test context to verify if GL_KHR_robustness extension is available */
65         {
66                 deqp::Context context(m_testCtx, glu::ContextType(m_ApiType));
67                 if (!context.getContextInfo().isExtensionSupported("GL_KHR_robustness") &&
68                         !contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
69                 {
70                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
71                                                                         "GL_KHR_robustness extension not supported");
72                         return NULL;
73                 }
74         }
75
76         glu::RenderConfig               renderCfg(glu::ContextType(m_ApiType, glu::CONTEXT_ROBUST));
77         const tcu::CommandLine& commandLine = m_testCtx.getCommandLine();
78         glu::parseRenderConfig(&renderCfg, commandLine);
79
80         if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW)
81                 renderCfg.resetNotificationStrategy = reset;
82         else
83                 throw tcu::NotSupportedError("Test not supported in non-windowed context");
84
85         /* Try to create core/es robusness context */
86         return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg);
87 }
88
89 class NoResetNotificationCase : public RobustnessBase
90 {
91         typedef glw::GLenum(GLW_APIENTRY* PFNGLGETGRAPHICSRESETSTATUS)();
92
93 public:
94         NoResetNotificationCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType)
95                 : RobustnessBase(testCtx, name, description, apiType)
96         {
97         }
98
99         virtual IterateResult iterate(void)
100         {
101                 glu::ResetNotificationStrategy  strategy = glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION;
102                 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy));
103                 if (!robustContext.get())
104                         return STOP;
105
106                 PFNGLGETGRAPHICSRESETSTATUS pGetGraphicsResetStatus =
107                         (PFNGLGETGRAPHICSRESETSTATUS)robustContext->getProcAddress("glGetGraphicsResetStatus");
108
109                 if (DE_NULL == pGetGraphicsResetStatus)
110                 {
111                         m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR,
112                                                                         "Pointer to function glGetGraphicsResetStatus is NULL.");
113                         return STOP;
114                 }
115
116                 glw::GLint reset = 0;
117
118                 const glw::Functions& gl = robustContext->getFunctions();
119                 gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
120                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
121
122                 if (reset != GL_NO_RESET_NOTIFICATION)
123                 {
124                         m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
125                                                            << ", expected " << GL_NO_RESET_NOTIFICATION << "]." << tcu::TestLog::EndMessage;
126
127                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
128                         return STOP;
129                 }
130
131                 glw::GLint status = pGetGraphicsResetStatus();
132                 if (status != GL_NO_ERROR)
133                 {
134                         m_testCtx.getLog() << tcu::TestLog::Message
135                                                            << "Test failed! glGetGraphicsResetStatus returned wrong value [" << status
136                                                            << ", expected " << GL_NO_ERROR << "]." << tcu::TestLog::EndMessage;
137
138                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
139                         return STOP;
140                 }
141
142                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
143                 return STOP;
144         }
145 };
146
147 class LoseContextOnResetCase : public RobustnessBase
148 {
149 public:
150         LoseContextOnResetCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType)
151                 : RobustnessBase(testCtx, name, description, apiType)
152         {
153         }
154
155         virtual IterateResult iterate(void)
156         {
157                 glu::ResetNotificationStrategy  strategy = glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET;
158                 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy));
159                 if (!robustContext.get())
160                         return STOP;
161
162                 glw::GLint reset = 0;
163
164                 const glw::Functions& gl = robustContext->getFunctions();
165                 gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
166                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
167
168                 if (reset != GL_LOSE_CONTEXT_ON_RESET)
169                 {
170                         m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
171                                                            << ", expected " << GL_LOSE_CONTEXT_ON_RESET << "]." << tcu::TestLog::EndMessage;
172
173                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
174                         return STOP;
175                 }
176
177                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
178                 return STOP;
179         }
180 };
181
182 } // ResetNotificationStrategy namespace
183
184 namespace RobustBufferAccessBehavior
185 {
186
187 static deqp::Context* createContext(tcu::TestContext& testCtx, glu::ApiType apiType)
188 {
189         deqp::Context* context = new deqp::Context(testCtx, glu::ContextType(apiType));
190         if (!context)
191         {
192                 testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to context is NULL.");
193                 return DE_NULL;
194         }
195
196         if (!(contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
197                   (context->getContextInfo().isExtensionSupported("GL_KHR_robustness") &&
198                    context->getContextInfo().isExtensionSupported("GL_KHR_robust_buffer_access_behavior"))))
199         {
200                 testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
201                 delete context;
202                 return DE_NULL;
203         }
204
205         return context;
206 }
207
208 /** Implementation of test GetnUniformTest. Description follows:
209  *
210  * This test verifies if read uniform variables to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error;
211  **/
212 class GetnUniformTest : public tcu::TestCase
213 {
214 public:
215         /* Public methods */
216         GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType);
217         virtual ~GetnUniformTest()
218         {
219         }
220
221         /* Public methods inherited from TestCase */
222         virtual tcu::TestNode::IterateResult iterate(void);
223
224 private:
225         /* Private methods */
226         std::string getComputeShader(bool glslES320);
227
228         bool verifyResult(const void* inputData, const void* resultData, int size, const char* method);
229         bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method);
230
231         glu::ApiType m_ApiType;
232 };
233
234 /** Constructor
235  *
236  * @param context Test context
237  **/
238 GetnUniformTest::GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType)
239         : tcu::TestCase(testCtx, "getnuniform", "Verifies if read uniform variables to the buffer with bufSize less than "
240                                                                                         "expected result with GL_INVALID_OPERATION")
241         , m_ApiType(apiType)
242 {
243         /* Nothing to be done here */
244 }
245
246 /** Execute test
247  *
248  * @return tcu::TestNode::STOP
249  **/
250 tcu::TestNode::IterateResult GetnUniformTest::iterate()
251 {
252         de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType));
253         if (!context.get())
254                 return STOP;
255
256         /* GL funtion pointers. */
257         typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMFV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
258                                                                                                         glw::GLfloat * params);
259         typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
260                                                                                                         glw::GLint * params);
261         typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMUIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
262                                                                                                          glw::GLuint * params);
263
264         /* Function pointers need to be grabbed only for GL4.5 but it is done also for ES for consistency */
265         glu::RenderContext& renderContext   = context->getRenderContext();
266         PFNGLGETNUNIFORMFV  pGetnUniformfv  = (PFNGLGETNUNIFORMFV)renderContext.getProcAddress("glGetnUniformfv");
267         PFNGLGETNUNIFORMIV  pGetnUniformiv  = (PFNGLGETNUNIFORMIV)renderContext.getProcAddress("glGetnUniformiv");
268         PFNGLGETNUNIFORMUIV pGetnUniformuiv = (PFNGLGETNUNIFORMUIV)renderContext.getProcAddress("glGetnUniformuiv");
269
270         if ((DE_NULL == pGetnUniformfv) || (DE_NULL == pGetnUniformiv) || (DE_NULL == pGetnUniformuiv))
271         {
272                 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glGetnUniform* is NULL.");
273                 return STOP;
274         }
275
276         const Functions& gl = renderContext.getFunctions();
277
278         const GLfloat input4f[]  = { 1.0f, 5.4f, 3.14159f, 1.28f };
279         const GLint   input3i[]  = { 10, -20, -30 };
280         const GLuint  input4ui[] = { 10, 20, 30, 40 };
281
282         /* Test result indicator */
283         bool test_result = true;
284
285         /* Iterate over all cases */
286         Program program(*context);
287
288         /* Compute Shader */
289         bool                       glslES320 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
290         const std::string& cs            = getComputeShader(glslES320);
291
292         /* Shaders initialization */
293         program.Init(cs /* cs */, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
294         program.Use();
295
296         /* For gl4.5 use shader storage buffer */
297         GLuint buf;
298         if (!glslES320)
299         {
300                 gl.genBuffers(1, &buf);
301                 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
302
303                 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buf);
304                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
305
306                 gl.bufferData(GL_SHADER_STORAGE_BUFFER, 16, DE_NULL, GL_STREAM_DRAW);
307                 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
308         }
309
310         /* passing uniform values */
311         gl.programUniform4fv(program.m_id, 11, 1, input4f);
312         GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4fv");
313
314         gl.programUniform3iv(program.m_id, 12, 1, input3i);
315         GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform3iv");
316
317         gl.programUniform4uiv(program.m_id, 13, 1, input4ui);
318         GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4uiv");
319
320         gl.dispatchCompute(1, 1, 1);
321         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
322
323         /* veryfing gfetnUniform error messages */
324         GLfloat result4f[4];
325         GLint   result3i[3];
326         GLuint  result4ui[4];
327
328         pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 4, result4f);
329         test_result = test_result &&
330                                   verifyResult((void*)input4f, (void*)result4f, sizeof(GLfloat) * 4, "getnUniformfv [false negative]");
331         test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformfv [false negative]");
332
333         pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 3, result4f);
334         test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformfv [false positive]");
335
336         pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 3, result3i);
337         test_result = test_result &&
338                                   verifyResult((void*)input3i, (void*)result3i, sizeof(GLint) * 3, "getnUniformiv [false negative]");
339         test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformiv [false negative]");
340
341         pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 2, result3i);
342         test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformiv [false positive]");
343
344         pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 4, result4ui);
345         test_result = test_result && verifyResult((void*)input4ui, (void*)result4ui, sizeof(GLuint) * 4,
346                                                                                           "getnUniformuiv [false negative]");
347         test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformuiv [false negative]");
348
349         pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 3, result4ui);
350         test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformuiv [false positive]");
351
352         /* Set result */
353         if (true == test_result)
354         {
355                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
356         }
357         else
358         {
359                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
360         }
361
362         if (!glslES320)
363         {
364                 gl.deleteBuffers(1, &buf);
365         }
366
367         /* Done */
368         return tcu::TestNode::STOP;
369 }
370
371 std::string GetnUniformTest::getComputeShader(bool glslES320)
372 {
373         std::stringstream shader;
374         shader << "#version " << (glslES320 ? "320 es\n" : "450\n");
375         shader << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
376                           "layout (location = 11) uniform vec4 inputf;\n"
377                           "layout (location = 12) uniform ivec3 inputi;\n"
378                           "layout (location = 13) uniform uvec4 inputu;\n";
379         if (glslES320)
380         {
381                 shader << "shared float valuef;\n"
382                                   "shared int valuei;\n"
383                                   "shared uint valueu;\n";
384         }
385         else
386         {
387                 shader << "layout (std140, binding = 0) buffer ssbo {"
388                                   "   float valuef;\n"
389                                   "   int valuei;\n"
390                                   "   uint valueu;\n"
391                                   "};\n";
392         }
393         shader << "void main()\n"
394                           "{\n"
395                           "   valuef = inputf.r + inputf.g + inputf.b + inputf.a;\n"
396                           "   valuei = inputi.r + inputi.g + inputi.b;\n"
397                           "   valueu = inputu.r + inputu.g + inputu.b + inputu.a;\n"
398                           "}\n";
399
400         return shader.str();
401 }
402
403 bool GetnUniformTest::verifyResult(const void* inputData, const void* resultData, int size, const char* method)
404 {
405         int diff = memcmp(inputData, resultData, size);
406         if (diff != 0)
407         {
408                 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " result is not as expected."
409                                                    << tcu::TestLog::EndMessage;
410
411                 return false;
412         }
413
414         return true;
415 }
416
417 bool GetnUniformTest::verifyError(GLint error, GLint expectedError, const char* method)
418 {
419         if (error != expectedError)
420         {
421                 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
422                                                    << error << "]." << tcu::TestLog::EndMessage;
423
424                 return false;
425         }
426
427         return true;
428 }
429
430 /** Implementation of test ReadnPixelsTest. Description follows:
431  *
432  * This test verifies if read pixels to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error;
433  **/
434 class ReadnPixelsTest : public tcu::TestCase
435 {
436 public:
437         /* Public methods */
438         ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType);
439         virtual ~ReadnPixelsTest()
440         {
441         }
442
443         /* Public methods inherited from TestCase */
444         virtual tcu::TestNode::IterateResult iterate(void);
445
446 private:
447         /* Private methods */
448         void cleanTexture(deqp::Context& context, glw::GLuint texture_id);
449         bool verifyResults(deqp::Context& context);
450         bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method);
451
452         glu::ApiType m_ApiType;
453 };
454
455 /** Constructor
456  *
457  * @param context Test context
458  **/
459 ReadnPixelsTest::ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
460         : tcu::TestCase(testCtx, "readnpixels",
461                                         "Verifies if read pixels to the buffer with bufSize less than expected result "
462                                         "with GL_INVALID_OPERATION error")
463         , m_ApiType(apiType)
464 {
465         /* Nothing to be done here */
466 }
467
468 /** Execute test
469  *
470  * @return tcu::TestNode::STOP
471  **/
472 tcu::TestNode::IterateResult ReadnPixelsTest::iterate()
473 {
474         de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType));
475         if (!context.get())
476                 return STOP;
477
478         /* GL funtion pointers. */
479         typedef void(GLW_APIENTRY * PFNGLREADNPIXELS)(glw::GLint x, glw::GLint y, glw::GLsizei width, glw::GLsizei height,
480                                                                                                   glw::GLenum format, glw::GLenum type, glw::GLsizei bufSize,
481                                                                                                   glw::GLvoid * data);
482
483         PFNGLREADNPIXELS pReadnPixels = (PFNGLREADNPIXELS)context->getRenderContext().getProcAddress("glReadnPixels");
484
485         if (DE_NULL == pReadnPixels)
486         {
487                 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glReadnPixels is NULL.");
488                 return STOP;
489         }
490
491         static const GLuint elements[] = {
492                 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
493         };
494
495         static const GLfloat vertices[] = {
496                 0.0f,  0.0f,  0.0f, 1.0f, /* 0 */
497                 -1.0f, 0.0f,  0.0f, 1.0f, /* 1 */
498                 -1.0f, 1.0f,  0.0f, 1.0f, /* 2 */
499                 0.0f,  1.0f,  0.0f, 1.0f, /* 3 */
500                 1.0f,  1.0f,  0.0f, 1.0f, /* 4 */
501                 1.0f,  0.0f,  0.0f, 1.0f, /* 5 */
502                 1.0f,  -1.0f, 0.0f, 1.0f, /* 6 */
503                 0.0f,  -1.0f, 0.0f, 1.0f, /* 7 */
504                 -1.0f, -1.0f, 0.0f, 1.0f, /* 8 */
505         };
506
507         bool glslES320 = contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2));
508         std::string fs("#version ");
509         fs += (glslES320 ? "320 es\n" : "450\n");
510         fs += "layout (location = 0) out lowp uvec4 out_fs_color;\n"
511                   "\n"
512                   "void main()\n"
513                   "{\n"
514                   "     out_fs_color = uvec4(1, 0, 0, 1);\n"
515                   "}\n"
516                   "\n";
517
518         std::string vs("#version ");
519         vs += (glslES320 ? "320 es\n" : "450\n");
520         vs += "layout (location = 0) in vec4 in_vs_position;\n"
521                   "\n"
522                   "void main()\n"
523                   "{\n"
524                   "     gl_Position = in_vs_position;\n"
525                   "}\n"
526                   "\n";
527
528         static const GLuint height       = 8;
529         static const GLuint width         = 8;
530         static const GLuint n_vertices = 24;
531
532         /* GL entry points */
533         const Functions& gl = context->getRenderContext().getFunctions();
534
535         /* Test case objects */
536         Program         program(*context);
537         Texture         texture(*context);
538         Buffer          elements_buffer(*context);
539         Buffer          vertices_buffer(*context);
540         VertexArray vao(*context);
541
542         /* Vertex array initialization */
543         VertexArray::Generate(gl, vao.m_id);
544         VertexArray::Bind(gl, vao.m_id);
545
546         /* Texture initialization */
547         Texture::Generate(gl, texture.m_id);
548         Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
549         Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
550         Texture::Bind(gl, 0, GL_TEXTURE_2D);
551
552         /* Framebuffer initialization */
553         GLuint fbo;
554         gl.genFramebuffers(1, &fbo);
555         GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
556         gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
557         GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
558         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_id, 0);
559         GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
560
561         /* Buffers initialization */
562         elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(elements), elements);
563         vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
564
565         /* Shaders initialization */
566         program.Init("" /* cs */, fs, "" /* gs */, "" /* tcs */, "" /* tes */, vs);
567         Program::Use(gl, program.m_id);
568
569         /* Vertex buffer initialization */
570         vertices_buffer.Bind();
571         gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 16 /* stride */);
572         gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 16, NULL);
573         gl.enableVertexAttribArray(0 /* location */);
574
575         /* Binding elements/indices buffer */
576         elements_buffer.Bind();
577
578         cleanTexture(*context, texture.m_id);
579
580         gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
581         GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
582
583         /* Set result */
584         if (verifyResults(*context))
585         {
586                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
587         }
588         else
589         {
590                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
591         }
592
593         /* Done */
594         return tcu::TestNode::STOP;
595 }
596
597 /** Fill texture with value 128
598  *
599  * @param texture_id Id of texture
600  **/
601 void ReadnPixelsTest::cleanTexture(deqp::Context& context, glw::GLuint texture_id)
602 {
603         static const GLuint height = 8;
604         static const GLuint width  = 8;
605
606         const Functions& gl = context.getRenderContext().getFunctions();
607
608         GLubyte pixels[width * height];
609         for (GLuint i = 0; i < width * height; ++i)
610         {
611                 pixels[i] = 64;
612         }
613
614         Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
615
616         Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level  */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
617                                           GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
618
619         /* Unbind */
620         Texture::Bind(gl, 0, GL_TEXTURE_2D);
621 }
622
623 /** Verifies glReadnPixels results
624  *
625  * @return true when glReadnPixels , false otherwise
626  **/
627 bool ReadnPixelsTest::verifyResults(deqp::Context& context)
628 {
629         static const GLuint height       = 8;
630         static const GLuint width         = 8;
631         static const GLuint pixel_size = 4 * sizeof(GLuint);
632
633         const Functions& gl = context.getRenderContext().getFunctions();
634
635         //Valid buffer size test
636         const GLint bufSizeValid = width * height * pixel_size;
637         GLubyte         pixelsValid[bufSizeValid];
638
639         gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeValid, pixelsValid);
640         GLU_EXPECT_NO_ERROR(gl.getError(), "ReadnPixels");
641
642         //Verify glReadnPixels result
643         for (unsigned int i = 0; i < width * height; ++i)
644         {
645                 const size_t offset = i * pixel_size;
646                 const GLuint value  = *(GLuint*)(pixelsValid + offset);
647
648                 if (value != 1)
649                 {
650                         context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel value: " << value
651                                                                                           << ". Offset: " << offset << tcu::TestLog::EndMessage;
652                         return false;
653                 }
654         }
655
656         //Invalid buffer size test
657         const GLint bufSizeInvalid = width * height * pixel_size - 1;
658         GLubyte         pixelsInvalid[bufSizeInvalid];
659
660         gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeInvalid, pixelsInvalid);
661         if (!verifyError(gl.getError(), GL_INVALID_OPERATION, "ReadnPixels [false positive]"))
662                 return false;
663
664         return true;
665 }
666
667 /** Verify operation errors
668  *
669  * @param error OpenGL ES error code
670  * @param expectedError Expected error code
671  * @param method Method name marker
672  *
673  * @return true when error is as expected, false otherwise
674  **/
675 bool ReadnPixelsTest::verifyError(GLint error, GLint expectedError, const char* method)
676 {
677         if (error != expectedError)
678         {
679                 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
680                                                    << error << "]." << tcu::TestLog::EndMessage;
681
682                 return false;
683         }
684
685         return true;
686 }
687
688 } // RobustBufferAccessBehavior namespace
689
690 RobustnessTests::RobustnessTests(tcu::TestContext& testCtx, glu::ApiType apiType)
691         : tcu::TestCaseGroup(testCtx, "robustness",
692                                                  "Verifies API coverage and functionality of GL_KHR_robustness extension.")
693         , m_ApiType(apiType)
694 {
695 }
696
697 void RobustnessTests::init(void)
698 {
699         tcu::TestCaseGroup::init();
700
701         try
702         {
703                 addChild(new ResetNotificationStrategy::NoResetNotificationCase(
704                         m_testCtx, "no_reset_notification", "Verifies if NO_RESET_NOTIFICATION strategy works as expected.",
705                         m_ApiType));
706                 addChild(new ResetNotificationStrategy::LoseContextOnResetCase(
707                         m_testCtx, "lose_context_on_reset", "Verifies if LOSE_CONTEXT_ON_RESET strategy works as expected.",
708                         m_ApiType));
709
710                 addChild(new RobustBufferAccessBehavior::GetnUniformTest(m_testCtx, m_ApiType));
711                 addChild(new RobustBufferAccessBehavior::ReadnPixelsTest(m_testCtx, m_ApiType));
712         }
713         catch (...)
714         {
715                 // Destroy context.
716                 tcu::TestCaseGroup::deinit();
717                 throw;
718         }
719 }
720
721 } // glcts namespace