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