Merge vk-gl-cts/opengl-cts-4.6.0 into vk-gl-cts/master
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / gles32 / es32cRobustBufferAccessBehaviorTests.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2016 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  es32cRobustBufferAccessBehaviorTests.cpp
21  * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
22  */ /*-------------------------------------------------------------------*/
23
24 #include "es32cRobustBufferAccessBehaviorTests.hpp"
25
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "gluStrUtil.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuTestLog.hpp"
32
33 #include <cstring>
34 #include <string>
35
36 using namespace glw;
37 using namespace deqp::RobustBufferAccessBehavior;
38
39 namespace es32cts
40 {
41 namespace RobustBufferAccessBehavior
42 {
43 /** Constructor
44  *
45  * @param context Test context
46  **/
47 VertexBufferObjectsTest::VertexBufferObjectsTest(deqp::Context& context)
48         : deqp::RobustBufferAccessBehavior::VertexBufferObjectsTest(
49                   context, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero")
50 {
51         /* Nothing to be done */
52 }
53
54 /** Prepare shader for current test case
55  *
56  * @return Source
57  **/
58 std::string VertexBufferObjectsTest::getFragmentShader()
59 {
60         return std::string("#version 320 es\n"
61                                            "\n"
62                                            "layout (location = 0) out lowp uvec4 out_fs_color;\n"
63                                            "\n"
64                                            "void main()\n"
65                                            "{\n"
66                                            "    out_fs_color = uvec4(1, 255, 255, 255);\n"
67                                            "}\n"
68                                            "\n");
69 }
70
71 /** Prepare shader for current test case
72  *
73  * @return Source
74  **/
75 std::string VertexBufferObjectsTest::getVertexShader()
76 {
77         return std::string("#version 320 es\n"
78                                            "\n"
79                                            "layout (location = 0) in vec4 in_vs_position;\n"
80                                            "\n"
81                                            "void main()\n"
82                                            "{\n"
83                                            "    gl_Position = in_vs_position;\n"
84                                            "}\n"
85                                            "\n");
86 }
87
88 /** No verification because of undefined out-of-bound behavior in OpenGL ES
89  *
90  * @param texture_id Id of texture
91  *
92  * @return true
93  **/
94 bool VertexBufferObjectsTest::verifyInvalidResults(glw::GLuint texture_id)
95 {
96         (void)texture_id;
97         return true;
98 }
99
100 /** Verifies that texutre is filled with 1
101  *
102  * @param texture_id Id of texture
103  *
104  * @return true when image is filled with 1, false otherwise
105  **/
106 bool VertexBufferObjectsTest::verifyResults(glw::GLuint texture_id)
107 {
108         static const GLuint height       = 8;
109         static const GLuint width         = 8;
110         static const GLuint pixel_size = 4 * sizeof(GLuint);
111
112         const Functions& gl = m_context.getRenderContext().getFunctions();
113
114         const GLint buf_size = width * height * pixel_size;
115         GLubyte         pixels[buf_size];
116         deMemset(pixels, 0, buf_size);
117
118         Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
119
120         Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, pixels);
121
122         /* Unbind */
123         Texture::Bind(gl, 0, GL_TEXTURE_2D);
124
125         /* Verify */
126         for (GLuint i = 0; i < buf_size; i += pixel_size)
127         {
128                 if (1 != pixels[i])
129                 {
130                         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)pixels[i]
131                                                                                                 << " at offset: " << i << tcu::TestLog::EndMessage;
132
133                         return false;
134                 }
135         }
136
137         return true;
138 }
139
140 /** Constructor
141  *
142  * @param context Test context
143  **/
144 TexelFetchTest::TexelFetchTest(deqp::Context& context)
145         : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, "texel_fetch",
146                                                                                                            "Verifies that out-of-bound fetches from texture result in zero")
147 {
148         /* Nothing to be done */
149 }
150
151 TexelFetchTest::TexelFetchTest(deqp::Context& context, const glw::GLchar* name, const glw::GLchar* description)
152         : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, name, description)
153 {
154         /* Nothing to be done */
155 }
156
157 /** Prepare shader for current test case
158  *
159  * @return Source
160  **/
161 std::string TexelFetchTest::getGeometryShader()
162 {
163         return std::string("#version 320 es\n"
164                                            "\n"
165                                            "layout(points)                           in;\n"
166                                            "layout(triangle_strip, max_vertices = 4) out;\n"
167                                            "\n"
168                                            "out vec2 gs_fs_tex_coord;\n"
169                                            "\n"
170                                            "void main()\n"
171                                            "{\n"
172                                            "    gs_fs_tex_coord = vec2(0, 0);\n"
173                                            "    gl_Position     = vec4(-1, -1, 0, 1);\n"
174                                            "    EmitVertex();\n"
175                                            "\n"
176                                            "    gs_fs_tex_coord = vec2(0, 1);\n"
177                                            "    gl_Position     = vec4(-1, 1, 0, 1);\n"
178                                            "    EmitVertex();\n"
179                                            "\n"
180                                            "    gs_fs_tex_coord = vec2(1, 0);\n"
181                                            "    gl_Position     = vec4(1, -1, 0, 1);\n"
182                                            "    EmitVertex();\n"
183                                            "\n"
184                                            "    gs_fs_tex_coord = vec2(1, 1);\n"
185                                            "    gl_Position     = vec4(1, 1, 0, 1);\n"
186                                            "    EmitVertex();\n"
187                                            "}\n"
188                                            "\n");
189 }
190
191 /** Prepare shader for current test case
192  *
193  * @return Source
194  **/
195 std::string TexelFetchTest::getVertexShader()
196 {
197         return std::string("#version 320 es\n"
198                                            "\n"
199                                            "void main()\n"
200                                            "{\n"
201                                            "    gl_Position = vec4(0, 0, 0, 1);\n"
202                                            "}\n"
203                                            "\n");
204 }
205
206 /** Prepare a texture
207  *
208  * @param is_source  Selects if texutre will be used as source or destination
209  * @param texture_id Id of texutre
210  **/
211 void TexelFetchTest::prepareTexture(bool is_source, glw::GLuint texture_id)
212 {
213         /* Image size */
214         static const GLuint image_height = 16;
215         static const GLuint image_width  = 16;
216
217         /* GL entry points */
218         const Functions& gl = m_context.getRenderContext().getFunctions();
219
220         /* Texture storage parameters */
221         GLuint  height                  = image_height;
222         GLenum  internal_format = 0;
223         GLsizei n_levels                = 1;
224         GLenum  target                  = GL_TEXTURE_2D;
225         GLuint  width                   = image_width;
226
227         /* Prepare texture storage parameters */
228         switch (m_test_case)
229         {
230         case R8:
231                 internal_format = GL_R8;
232                 break;
233         case RG8_SNORM:
234                 internal_format = GL_RG8_SNORM;
235                 break;
236         case RGBA32F:
237                 internal_format = GL_RGBA32F;
238                 break;
239         case R32UI_MIPMAP:
240                 height                  = 2 * image_height;
241                 internal_format = GL_R32UI;
242                 n_levels                = 2;
243                 width                   = 2 * image_width;
244                 break;
245         case R32UI_MULTISAMPLE:
246                 internal_format = GL_R32UI;
247                 n_levels                = 4;
248                 target                  = GL_TEXTURE_2D_MULTISAMPLE;
249                 break;
250         default:
251                 TCU_FAIL("Invalid enum");
252         }
253
254         /* Prepare storage */
255         Texture::Bind(gl, texture_id, target);
256         Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
257
258         /* Set samplers to NEAREST/NEAREST if required */
259         if (R32UI_MULTISAMPLE != m_test_case)
260         {
261                 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
262                 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
263         }
264
265         /* Destination image can be left empty */
266         if (false == is_source)
267         {
268                 Texture::Bind(gl, 0, target);
269                 return;
270         }
271
272         /* Prepare texture */
273         if (R8 == m_test_case)
274         {
275                 GLubyte source_pixels[image_width * image_height];
276                 for (GLuint i = 0; i < image_width * image_height; ++i)
277                 {
278                         source_pixels[i] = (GLubyte)i;
279                 }
280
281                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
282                                                   0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
283         }
284         else if (RG8_SNORM == m_test_case)
285         {
286                 static const GLuint n_components = 2;
287
288                 GLbyte source_pixels[image_width * image_height * n_components];
289                 for (GLuint i = 0; i < image_width * image_height; ++i)
290                 {
291                         source_pixels[i * n_components + 0] = (GLubyte)((i % 16));
292                         source_pixels[i * n_components + 1] = (GLubyte)((i / 16));
293                 }
294
295                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
296                                                   0 /* depth */, GL_RG, GL_BYTE, source_pixels);
297         }
298         else if (RGBA32F == m_test_case)
299         {
300                 static const GLuint n_components = 4;
301
302                 GLfloat source_pixels[image_width * image_height * n_components];
303                 for (GLuint i = 0; i < image_width * image_height; ++i)
304                 {
305                         source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
306                         source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
307                         source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
308                         source_pixels[i * n_components + 3] = 1.0f;
309                 }
310
311                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
312                                                   0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
313         }
314         else if (R32UI_MIPMAP == m_test_case)
315         {
316                 GLuint source_pixels[image_width * image_height];
317                 for (GLuint i = 0; i < image_width * image_height; ++i)
318                 {
319                         source_pixels[i] = i;
320                 }
321
322                 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
323                                                   0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
324
325                 /* texelFetch() undefined if the computed level of detail is not the texture’s base level and the texture’s
326                         minification filter is NEAREST or LINEAR */
327                 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
328         }
329         else if (R32UI_MULTISAMPLE == m_test_case)
330         {
331                 /* Compute Shader */
332                 static const GLchar* cs = "#version 320 es\n"
333                                                                   "\n"
334                                                                   "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"
335                                                                   "\n"
336                                                                   "layout (binding = 0, r32ui) writeonly uniform highp uimage2DMS uni_image;\n"
337                                                                   "\n"
338                                                                   "void main()\n"
339                                                                   "{\n"
340                                                                   "    ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
341                                                                   "    uint  index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
342                                                                   "\n"
343                                                                   "    imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
344                                                                   "    imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
345                                                                   "    imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
346                                                                   "    imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
347                                                                   "}\n"
348                                                                   "\n";
349
350                 Program program(m_context);
351                 program.Init(cs, "", "", "", "", "");
352                 program.Use();
353
354                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
355                                                         GL_WRITE_ONLY, GL_R32UI);
356                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
357
358                 gl.dispatchCompute(16, 16, 1);
359                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
360         }
361
362         Texture::Bind(gl, 0, target);
363 }
364
365 /** No verification because of undefined out-of-bound behavior in OpenGL ES
366  *
367  * @param texture_id Id of texture
368  *
369  * @return true
370  **/
371 bool TexelFetchTest::verifyInvalidResults(glw::GLuint texture_id)
372 {
373         (void)texture_id;
374         return true;
375 }
376
377 /** Verifies that texutre is filled with increasing values
378  *
379  * @param texture_id Id of texture
380  *
381  * @return true when image is filled with increasing values, false otherwise
382  **/
383 bool TexelFetchTest::verifyValidResults(glw::GLuint texture_id)
384 {
385         static const GLuint height   = 16;
386         static const GLuint width       = 16;
387         static const GLuint n_pixels = height * width;
388
389         const Functions& gl = m_context.getRenderContext().getFunctions();
390
391         bool result = true;
392
393         if (R8 == m_test_case)
394         {
395                 static const GLuint n_channels = 4;
396
397                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
398
399                 std::vector<GLubyte> pixels;
400                 pixels.resize(n_pixels * n_channels);
401                 for (GLuint i = 0; i < n_pixels; ++i)
402                 {
403                         pixels[i] = (GLubyte)i;
404                 }
405
406                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
407
408                 /* Unbind */
409                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
410
411                 /* Verify */
412                 for (GLuint i = 0; i < n_pixels; ++i)
413                 {
414                         const GLubyte expected_red = (GLubyte)i;
415                         const GLubyte drawn_red = pixels[i * n_channels];
416
417                         if (expected_red != drawn_red)
418                         {
419                                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
420                                                                                                         << ". Expected value: " << (GLuint)expected_red
421                                                                                                         << " at offset: " << i << tcu::TestLog::EndMessage;
422
423                                 result = false;
424                                 break;
425                         }
426                 }
427         }
428         else if (RG8_SNORM == m_test_case)
429         {
430                 static const GLuint n_channels = 4;
431
432                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
433
434                 std::vector<GLubyte> pixels;
435                 pixels.resize(n_pixels * n_channels);
436                 for (GLuint i = 0; i < n_pixels; ++i)
437                 {
438                         pixels[i * n_channels + 0] = (GLubyte)i;
439                         pixels[i * n_channels + 1] = (GLubyte)i;
440                 }
441
442                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
443
444                 /* Unbind */
445                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
446
447                 /* Verify */
448                 for (GLuint i = 0; i < n_pixels; ++i)
449                 {
450                         const GLbyte expected_red   = (GLubyte)(i % 16);
451                         const GLbyte expected_green = (GLubyte)(i / 16);
452                         const GLbyte drawn_red          = pixels[i * n_channels + 0];
453                         const GLbyte drawn_green        = pixels[i * n_channels + 1];
454
455                         if ((expected_red != drawn_red) || (expected_green != drawn_green))
456                         {
457                                 m_context.getTestContext().getLog()
458                                         << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " << (GLint)drawn_green
459                                         << ". Expected value: " << (GLint)expected_red << ", " << (GLint)expected_green
460                                         << ". At offset: " << i << tcu::TestLog::EndMessage;
461
462                                 result = false;
463                                 break;
464                         }
465                 }
466         }
467         else if (RGBA32F == m_test_case)
468         {
469                 static const GLuint n_channels = 4;
470
471                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
472
473                 std::vector<GLfloat> pixels;
474                 pixels.resize(n_pixels * n_channels);
475                 for (GLuint i = 0; i < n_pixels; ++i)
476                 {
477                         pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
478                         pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
479                         pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
480                         pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
481                 }
482
483                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
484
485                 /* Unbind */
486                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
487
488                 /* Verify */
489                 for (GLuint i = 0; i < n_pixels; ++i)
490                 {
491                         const GLfloat expected_red   = (GLfloat)(i % 16) / 16.0f;
492                         const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
493                         const GLfloat expected_blue  = (GLfloat)i / 256.0f;
494                         const GLfloat expected_alpha = 1.0f;
495                         const GLfloat drawn_red          = pixels[i * n_channels + 0];
496                         const GLfloat drawn_green       = pixels[i * n_channels + 1];
497                         const GLfloat drawn_blue         = pixels[i * n_channels + 2];
498                         const GLfloat drawn_alpha       = pixels[i * n_channels + 3];
499
500                         if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
501                                 (expected_alpha != drawn_alpha))
502                         {
503                                 m_context.getTestContext().getLog()
504                                         << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
505                                         << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
506                                         << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
507                                         << tcu::TestLog::EndMessage;
508
509                                 result = false;
510                                 break;
511                         }
512                 }
513         }
514         else if (R32UI_MIPMAP == m_test_case)
515         {
516                 static const GLuint n_channels = 4;
517
518                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
519
520                 std::vector<GLuint> pixels;
521                 pixels.resize(n_pixels * n_channels);
522                 deMemset(&pixels[0], 0, n_pixels * n_channels * sizeof(GLuint));
523
524                 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
525
526                 /* Unbind */
527                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
528
529                 /* Verify */
530                 for (GLuint i = 0; i < n_pixels; ++i)
531                 {
532                         const GLuint expected_red = i;
533                         const GLuint drawn_red  = pixels[i * n_channels];
534
535                         if (expected_red != drawn_red)
536                         {
537                                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
538                                                                                                         << ". Expected value: " << expected_red << " at offset: " << i
539                                                                                                         << tcu::TestLog::EndMessage;
540
541                                 result = false;
542                                 break;
543                         }
544                 }
545         }
546         else if (R32UI_MULTISAMPLE == m_test_case)
547         {
548                 static const GLuint n_channels = 4;
549
550                 /* Compute Shader */
551                 static const GLchar* cs =
552                         "#version 320 es\n"
553                         "\n"
554                         "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
555                         "\n"
556                         "layout (binding = 1, r32ui) writeonly uniform lowp uimage2D   uni_destination_image;\n"
557                         "layout (binding = 0, r32ui) readonly  uniform lowp uimage2DMS uni_source_image;\n"
558                         "\n"
559                         "void main()\n"
560                         "{\n"
561                         "    ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
562                         "    uint  index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
563                         "\n"
564                         "    uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
565                         "    uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
566                         "    uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
567                         "    uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
568                         "\n"
569                         "    if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
570                         "    {\n"
571                         "        imageStore(uni_destination_image, point, uvec4(1U));\n"
572                         "    }\n"
573                         "    else\n"
574                         "    {\n"
575                         "        imageStore(uni_destination_image, point, uvec4(0U));\n"
576                         "    }\n"
577                         "}\n"
578                         "\n";
579
580                 Program program(m_context);
581                 Texture destination_texture(m_context);
582
583                 Texture::Generate(gl, destination_texture.m_id);
584                 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
585                 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
586
587                 program.Init(cs, "", "", "", "", "");
588                 program.Use();
589                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
590                                                         GL_READ_ONLY, GL_R32UI);
591                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
592                 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
593                                                         0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
594                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
595
596                 gl.dispatchCompute(16, 16, 1);
597                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
598
599                 /* Pixels buffer initialization */
600                 std::vector<GLuint> pixels;
601                 pixels.resize(n_pixels * n_channels);
602                 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
603                 {
604                         pixels[i] = i;
605                 }
606
607                 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
608                                                  &pixels[0]);
609
610                 /* Unbind */
611                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
612
613                 /* Verify */
614                 for (GLuint i = 0; i < n_pixels; ++i)
615                 {
616                         const GLuint expected_red = 1;
617                         const GLuint drawn_red  = pixels[i * n_channels];
618
619                         if (expected_red != drawn_red)
620                         {
621                                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
622                                                                                                         << ". Expected value: " << expected_red << " at offset: " << i
623                                                                                                         << tcu::TestLog::EndMessage;
624
625                                 result = false;
626                                 break;
627                         }
628                 }
629         }
630
631         return result;
632 }
633
634 /** Constructor
635  *
636  * @param context Test context
637  **/
638 ImageLoadStoreTest::ImageLoadStoreTest(deqp::Context& context)
639         : TexelFetchTest(context, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded")
640 {
641         /* start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported under GLES */
642         m_test_case = RGBA32F;
643 }
644
645 /** Execute test
646  *
647  * @return tcu::TestNode::STOP
648  **/
649 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
650 {
651         if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_robust_buffer_access_behavior"))
652         {
653                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
654                 return STOP;
655         }
656
657         /* Constants */
658         static const GLuint height = 16;
659         static const GLuint width  = 16;
660
661         /* GL entry points */
662         const Functions& gl = m_context.getRenderContext().getFunctions();
663
664         const unsigned int coord_offsets[] = {
665                 16, 512, 1024, 2048,
666         };
667
668         /* Test result indicator */
669         bool test_result = true;
670
671         /* Iterate over all cases */
672         while (LAST != m_test_case)
673         {
674                 /* Test case result indicator */
675                 bool case_result = true;
676
677                 /* Test case objects */
678                 Texture destination_texture(m_context);
679                 Texture source_texture(m_context);
680                 Program program(m_context);
681
682                 /* Prepare textures */
683                 Texture::Generate(gl, destination_texture.m_id);
684                 Texture::Generate(gl, source_texture.m_id);
685
686                 prepareTexture(false, destination_texture.m_id);
687                 prepareTexture(true, source_texture.m_id);
688
689                 /* Test invalid source cases */
690                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(coord_offsets); ++i)
691                 {
692                         const std::string& cs = getComputeShader(SOURCE_INVALID, coord_offsets[i]);
693                         program.Init(cs, "", "", "", "", "");
694                         program.Use();
695
696                         /* Set texture */
697                         setTextures(destination_texture.m_id, source_texture.m_id);
698
699                         /* Dispatch */
700                         gl.dispatchCompute(width, height, 1 /* depth */);
701                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
702
703                         /* Verification */
704                         if (false == verifyInvalidResults(destination_texture.m_id))
705                         {
706                                 case_result = false;
707                         }
708                 }
709
710                 /* Test valid case */
711                 program.Init(getComputeShader(VALID), "", "", "", "", "");
712                 program.Use();
713
714                 /* Set texture */
715                 setTextures(destination_texture.m_id, source_texture.m_id);
716
717                 /* Dispatch */
718                 gl.dispatchCompute(width, height, 1 /* depth */);
719                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
720
721                 /* Verification */
722                 if (false == verifyValidResults(destination_texture.m_id))
723                 {
724                         case_result = false;
725                 }
726
727                 /* Test invalid destination cases */
728                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(coord_offsets); ++i)
729                 {
730                         const std::string& cs = getComputeShader(DESTINATION_INVALID, coord_offsets[i]);
731                         program.Init(cs, "", "", "", "", "");
732                         program.Use();
733
734                         /* Set texture */
735                         setTextures(destination_texture.m_id, source_texture.m_id);
736
737                         /* Dispatch */
738                         gl.dispatchCompute(width, height, 1 /* depth */);
739                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
740
741                         /* Verification */
742                         if (false == verifyValidResults(destination_texture.m_id))
743                         {
744                                 case_result = false;
745                         }
746                 }
747
748                 /* Set test result */
749                 if (false == case_result)
750                 {
751                         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName()
752                                                                                                 << " failed" << tcu::TestLog::EndMessage;
753
754                         test_result = false;
755                 }
756
757                 /* Increment */
758                 m_test_case = (TEST_CASES)((GLuint)m_test_case + 1);
759         }
760
761         /* Set result */
762         if (true == test_result)
763         {
764                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
765         }
766         else
767         {
768                 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
769         }
770
771         /* Done */
772         return tcu::TestNode::STOP;
773 }
774
775 /** Prepare shader for current test case
776  *
777  * @param version Specify which version should be prepared
778  *
779  * @return Source
780  **/
781 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset)
782 {
783         static const GLchar* template_code =
784                 "#version 320 es\n"
785                 "\n"
786                 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
787                 "\n"
788                 "layout (binding = 1, FORMAT) writeonly uniform highp IMAGE uni_destination_image;\n"
789                 "layout (binding = 0, FORMAT) readonly  uniform highp IMAGE uni_source_image;\n"
790                 "\n"
791                 "void main()\n"
792                 "{\n"
793                 "    ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(COORD_OFFSETU);\n"
794                 "    ivec2 point_source      = ivec2(gl_WorkGroupID.xy) + ivec2(COORD_OFFSETU);\n"
795                 "\n"
796                 "COPY"
797                 "}\n"
798                 "\n";
799
800         static const GLchar* copy_regular = "    TYPE color = imageLoad(uni_source_image, point_source);\n"
801                                                                                 "    imageStore(uni_destination_image, point_destination, color);\n";
802
803         static const GLchar* format_rgba32f = "rgba32f";
804         static const GLchar* format_r32ui   = "r32ui";
805
806         static const GLchar* image_vec4 = "image2D";
807
808         static const GLchar* image_uvec4 = "uimage2D";
809
810         static const GLchar* type_vec4  = "vec4";
811         static const GLchar* type_uvec4 = "uvec4";
812
813         const GLchar* copy                               = copy_regular;
814         const GLchar* format                     = format_rgba32f;
815         const GLchar* image                              = image_vec4;
816         const GLchar* type                               = type_vec4;
817         const GLchar* src_coord_offset   = "0";
818         const GLchar* dst_coord_offset   = "0";
819
820         std::stringstream coord_offset_stream;
821         coord_offset_stream << coord_offset;
822         std::string coord_offset_str = coord_offset_stream.str();
823
824         if (version == SOURCE_INVALID)
825                 src_coord_offset = coord_offset_str.c_str();
826         else if (version == DESTINATION_INVALID)
827                 dst_coord_offset = coord_offset_str.c_str();
828
829         switch (m_test_case)
830         {
831         case RGBA32F:
832                 format = format_rgba32f;
833                 break;
834         case R32UI_MIPMAP:
835                 format = format_r32ui;
836                 image  = image_uvec4;
837                 type   = type_uvec4;
838                 break;
839         default:
840                 TCU_FAIL("Invalid enum");
841         };
842
843         size_t          position = 0;
844         std::string source   = template_code;
845
846         replaceToken("FORMAT", position, format, source);
847         replaceToken("IMAGE", position, image, source);
848         replaceToken("FORMAT", position, format, source);
849         replaceToken("IMAGE", position, image, source);
850         replaceToken("COORD_OFFSET", position, dst_coord_offset, source);
851         replaceToken("COORD_OFFSET", position, src_coord_offset, source);
852
853         size_t temp_position = position;
854         replaceToken("COPY", position, copy, source);
855         position = temp_position;
856
857         switch (m_test_case)
858         {
859         case RGBA32F:
860         case R32UI_MIPMAP:
861                 replaceToken("TYPE", position, type, source);
862                 break;
863         default:
864                 TCU_FAIL("Invalid enum");
865         }
866
867         return source;
868 }
869
870 /** Set textures as images
871  *
872  * @param id_destination Id of texture used as destination
873  * @param id_source      Id of texture used as source
874  **/
875 void ImageLoadStoreTest::setTextures(glw::GLuint id_destination, glw::GLuint id_source)
876 {
877         const Functions& gl = m_context.getRenderContext().getFunctions();
878
879         GLenum format = 0;
880         GLint  level  = 0;
881
882         switch (m_test_case)
883         {
884         case RGBA32F:
885                 format = GL_RGBA32F;
886                 break;
887         case R32UI_MIPMAP:
888                 format = GL_R32UI;
889                 level  = 1;
890                 break;
891         default:
892                 TCU_FAIL("Invalid enum");
893         }
894
895         gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
896         GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
897
898         gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
899                                                 format);
900         GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
901 }
902
903 /** No verification because of undefined out-of-bound behavior in OpenGL ES
904  *
905  * @param texture_id Id of texture
906  *
907  * @return true
908  **/
909 bool ImageLoadStoreTest::verifyInvalidResults(glw::GLuint texture_id)
910 {
911         (void)texture_id;
912         return true;
913 }
914
915 /** Verifies that texutre is filled with increasing values
916  *
917  * @param texture_id Id of texture
918  *
919  * @return true when image is filled with increasing values, false otherwise
920  **/
921 bool ImageLoadStoreTest::verifyValidResults(glw::GLuint texture_id)
922 {
923         static const GLuint height   = 16;
924         static const GLuint width       = 16;
925         static const GLuint n_pixels = height * width;
926
927         const Functions& gl = m_context.getRenderContext().getFunctions();
928         gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
929         GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
930
931         bool result = true;
932
933         if (RGBA32F == m_test_case)
934         {
935                 static const GLuint n_channels = 4;
936
937                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
938
939                 std::vector<GLfloat> pixels;
940                 pixels.resize(n_pixels * n_channels);
941                 for (GLuint i = 0; i < n_pixels; ++i)
942                 {
943                         pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
944                         pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
945                         pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
946                         pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
947                 }
948
949                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
950
951                 /* Unbind */
952                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
953
954                 /* Verify */
955                 for (GLuint i = 0; i < n_pixels; ++i)
956                 {
957                         const GLfloat expected_red   = (GLfloat)(i % 16) / 16.0f;
958                         const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
959                         const GLfloat expected_blue  = (GLfloat)i / 256.0f;
960                         const GLfloat expected_alpha = 1.0f;
961                         const GLfloat drawn_red          = pixels[i * n_channels + 0];
962                         const GLfloat drawn_green       = pixels[i * n_channels + 1];
963                         const GLfloat drawn_blue         = pixels[i * n_channels + 2];
964                         const GLfloat drawn_alpha       = pixels[i * n_channels + 3];
965
966                         if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
967                                 (expected_alpha != drawn_alpha))
968                         {
969                                 m_context.getTestContext().getLog()
970                                         << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
971                                         << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
972                                         << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
973                                         << tcu::TestLog::EndMessage;
974
975                                 result = false;
976                                 break;
977                         }
978                 }
979         }
980         else if (R32UI_MIPMAP == m_test_case)
981         {
982                 static const GLuint n_channels = 4;
983
984                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
985
986                 std::vector<GLuint> pixels;
987                 pixels.resize(n_pixels * n_channels);
988                 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
989                 {
990                         pixels[i] = 0;
991                 }
992
993                 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
994
995                 /* Unbind */
996                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
997
998                 /* Verify */
999                 for (GLuint i = 0; i < n_pixels; ++i)
1000                 {
1001                         const GLuint expected_red = i;
1002                         const GLuint drawn_red  = pixels[i * n_channels];
1003
1004                         if (expected_red != drawn_red)
1005                         {
1006                                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
1007                                                                                                         << ". Expected value: " << expected_red << " at offset: " << i
1008                                                                                                         << tcu::TestLog::EndMessage;
1009
1010                                 result = false;
1011                                 break;
1012                         }
1013                 }
1014         }
1015
1016         return result;
1017 }
1018
1019 /** Constructor
1020  *
1021  * @param context Test context
1022  **/
1023 StorageBufferTest::StorageBufferTest(deqp::Context& context)
1024         : deqp::RobustBufferAccessBehavior::StorageBufferTest(
1025                   context, "storage_buffer", "Verifies that out-of-bound access to SSBO results with no error")
1026 {
1027         /* Nothing to be done here */
1028 }
1029
1030 /** Prepare shader for current test case
1031  *
1032  * @return Source
1033  **/
1034 std::string StorageBufferTest::getComputeShader(glw::GLuint offset)
1035 {
1036         static const GLchar* cs = "#version 320 es\n"
1037                                                           "\n"
1038                                                           "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1039                                                           "\n"
1040                                                           "layout (binding = 1) buffer Source {\n"
1041                                                           "    float data[];\n"
1042                                                           "} source;\n"
1043                                                           "\n"
1044                                                           "layout (binding = 0) buffer Destination {\n"
1045                                                           "    float data[];\n"
1046                                                           "} destination;\n"
1047                                                           "\n"
1048                                                           "void main()\n"
1049                                                           "{\n"
1050                                                           "    uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1051                                                           "    uint index_source      = gl_LocalInvocationID.x + OFFSETU;\n"
1052                                                           "\n"
1053                                                           "    destination.data[index_destination] = source.data[index_source];\n"
1054                                                           "}\n"
1055                                                           "\n";
1056
1057         std::string   destination_offset("0");
1058         std::string   source_offset("0");
1059         size_t            position = 0;
1060         std::string   source   = cs;
1061
1062         std::stringstream offset_stream;
1063         offset_stream << offset;
1064
1065         if (m_test_case == SOURCE_INVALID)
1066                 source_offset = offset_stream.str();
1067         else if (m_test_case == DESTINATION_INVALID)
1068                 destination_offset = offset_stream.str();
1069
1070         replaceToken("OFFSET", position, destination_offset.c_str(), source);
1071         replaceToken("OFFSET", position, source_offset.c_str(), source);
1072
1073         return source;
1074 }
1075
1076 /** Verify test case results
1077  *
1078  * @param buffer_data Buffer data to verify
1079  *
1080  * @return true if buffer_data is as expected, false othrewise
1081  **/
1082 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
1083 {
1084         static const GLfloat expected_data_valid[4]                               = { 2.0f, 3.0f, 4.0f, 5.0f };
1085         static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1086         static const GLfloat expected_data_invalid_source[4]      = { 0.0f, 0.0f, 0.0f, 0.0f };
1087
1088         int size = sizeof(GLfloat) * 4;
1089
1090         /* Prepare expected data const for proper case*/
1091         const GLfloat* expected_data = 0;
1092         const GLchar*  name                      = 0;
1093         switch (m_test_case)
1094         {
1095         case VALID:
1096                 expected_data = expected_data_valid;
1097                 name              = "valid indices";
1098                 break;
1099         case SOURCE_INVALID:
1100                 expected_data = expected_data_invalid_source;
1101                 name              = "invalid source indices";
1102                 break;
1103         case DESTINATION_INVALID:
1104                 expected_data = expected_data_invalid_destination;
1105                 name              = "invalid destination indices";
1106                 break;
1107         default:
1108                 TCU_FAIL("Invalid enum");
1109         }
1110
1111         /* Verify buffer data */
1112         if (m_test_case == VALID && memcmp(expected_data, buffer_data, size) != 0)
1113         {
1114                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
1115                                                                                         << tcu::TestLog::EndMessage;
1116                 return false;
1117         }
1118
1119         return true;
1120 }
1121
1122 /** Constructor
1123  *
1124  * @param context Test context
1125  **/
1126 UniformBufferTest::UniformBufferTest(deqp::Context& context)
1127         : deqp::RobustBufferAccessBehavior::UniformBufferTest(
1128                   context, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls with no error")
1129 {
1130         /* Nothing to be done here */
1131 }
1132
1133 /** Prepare shader for current test case
1134  *
1135  * @return Source
1136  **/
1137 std::string UniformBufferTest::getComputeShader(GLuint offset)
1138 {
1139         static const GLchar* cs = "#version 320 es\n"
1140                                                           "\n"
1141                                                           "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1142                                                           "\n"
1143                                                           "layout (binding = 0, std140) uniform Source {\n"
1144                                                           "    float data[16];\n"
1145                                                           "} source;\n"
1146                                                           "\n"
1147                                                           "layout (binding = 0, std430) buffer Destination {\n"
1148                                                           "    float data[];\n"
1149                                                           "} destination;\n"
1150                                                           "\n"
1151                                                           "void main()\n"
1152                                                           "{\n"
1153                                                           "    uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1154                                                           "    uint index_source      = gl_LocalInvocationID.x + OFFSETU;\n"
1155                                                           "\n"
1156                                                           "    destination.data[index_destination] = source.data[index_source];\n"
1157                                                           "}\n"
1158                                                           "\n";
1159
1160         const GLchar* destination_offset = "0";
1161         std::string   source_offset("0");
1162         size_t            position = 0;
1163         std::string   source   = cs;
1164
1165         std::stringstream offset_stream;
1166         offset_stream << offset;
1167
1168         if (m_test_case == SOURCE_INVALID)
1169                 source_offset = offset_stream.str();
1170
1171         replaceToken("OFFSET", position, destination_offset, source);
1172         replaceToken("OFFSET", position, source_offset.c_str(), source);
1173
1174         return source;
1175 }
1176
1177 } /* RobustBufferAccessBehavior */
1178
1179 /** Constructor.
1180  *
1181  *  @param context Rendering context.
1182  **/
1183 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(deqp::Context& context)
1184         : deqp::RobustBufferAccessBehaviorTests(context)
1185 {
1186         /* Left blank on purpose */
1187 }
1188
1189 /** Initializes a multi_bind test group.
1190  *
1191  **/
1192 void RobustBufferAccessBehaviorTests::init(void)
1193 {
1194         addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_context));
1195         addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_context));
1196         addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_context));
1197         addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_context));
1198         addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_context));
1199 }
1200
1201 } /* es32cts namespace */