Block/non-block uniforms match
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / glcRobustBufferAccessBehaviorTests.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  glcRobustBufferAccessBehaviorTests.cpp
21  * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
22  */ /*-------------------------------------------------------------------*/
23
24 #include "glcRobustBufferAccessBehaviorTests.hpp"
25
26 #include "deSharedPtr.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluDefs.hpp"
29 #include "gluShaderUtil.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "tcuTestLog.hpp"
35
36 #include <cstring>
37 #include <string>
38
39 using namespace glw;
40
41 namespace glcts
42 {
43 namespace RobustBufferAccessBehavior
44 {
45 /* Buffer constants */
46 const GLuint Buffer::m_invalid_id = -1;
47
48 const GLenum Buffer::m_targets[Buffer::m_n_targets] = {
49         GL_ARRAY_BUFFER,                          /*  0 */
50         GL_ATOMIC_COUNTER_BUFFER,        /*  1 */
51         GL_COPY_READ_BUFFER,              /*  2 */
52         GL_COPY_WRITE_BUFFER,             /*  3 */
53         GL_DISPATCH_INDIRECT_BUFFER,  /*  4 */
54         GL_DRAW_INDIRECT_BUFFER,          /*  5 */
55         GL_ELEMENT_ARRAY_BUFFER,          /*  6 */
56         GL_PIXEL_PACK_BUFFER,             /*  7 */
57         GL_PIXEL_UNPACK_BUFFER,           /*  8 */
58         GL_QUERY_BUFFER,                          /*  9 */
59         GL_SHADER_STORAGE_BUFFER,        /* 10 */
60         GL_TRANSFORM_FEEDBACK_BUFFER, /* 11 */
61         GL_UNIFORM_BUFFER,                        /* 12 */
62 };
63
64 /** Constructor.
65  *
66  * @param context CTS context.
67  **/
68 Buffer::Buffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl), m_target(GL_ARRAY_BUFFER)
69 {
70 }
71
72 /** Destructor
73  *
74  **/
75 Buffer::~Buffer()
76 {
77         Release();
78 }
79
80 /** Initialize buffer instance
81  *
82  * @param target Buffer target
83  * @param usage  Buffer usage enum
84  * @param size   <size> parameter
85  * @param data   <data> parameter
86  **/
87 void Buffer::InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data)
88 {
89         /* Delete previous buffer instance */
90         Release();
91
92         m_target = target;
93
94         Generate(m_gl, m_id);
95         Bind(m_gl, m_id, m_target);
96         Data(m_gl, m_target, usage, size, data);
97 }
98
99 /** Release buffer instance
100  *
101  **/
102 void Buffer::Release()
103 {
104         if (m_invalid_id != m_id)
105         {
106                 m_gl.deleteBuffers(1, &m_id);
107                 m_id = m_invalid_id;
108         }
109 }
110
111 /** Binds buffer to its target
112  *
113  **/
114 void Buffer::Bind() const
115 {
116         Bind(m_gl, m_id, m_target);
117 }
118
119 /** Binds indexed buffer
120  *
121  * @param index <index> parameter
122  **/
123 void Buffer::BindBase(glw::GLuint index) const
124 {
125         BindBase(m_gl, m_id, m_target, index);
126 }
127
128 /** Bind buffer to given target
129  *
130  * @param gl     GL functions
131  * @param id     Id of buffer
132  * @param target Buffer target
133  **/
134 void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
135 {
136         gl.bindBuffer(target, id);
137         GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
138 }
139
140 /** Binds indexed buffer
141  *
142  * @param gl     GL functions
143  * @param id     Id of buffer
144  * @param target Buffer target
145  * @param index  <index> parameter
146  **/
147 void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index)
148 {
149         gl.bindBufferBase(target, index, id);
150         GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
151 }
152
153 /** Allocate memory for buffer and sends initial content
154  *
155  * @param gl     GL functions
156  * @param target Buffer target
157  * @param usage  Buffer usage enum
158  * @param size   <size> parameter
159  * @param data   <data> parameter
160  **/
161 void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
162                                   const glw::GLvoid* data)
163 {
164         gl.bufferData(target, size, data, usage);
165         GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
166 }
167
168 /** Generate buffer
169  *
170  * @param gl     GL functions
171  * @param out_id Id of buffer
172  **/
173 void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
174 {
175         GLuint id = m_invalid_id;
176
177         gl.genBuffers(1, &id);
178         GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
179
180         if (m_invalid_id == id)
181         {
182                 TCU_FAIL("Got invalid id");
183         }
184
185         out_id = id;
186 }
187
188 /** Update range of buffer
189  *
190  * @param gl     GL functions
191  * @param target Buffer target
192  * @param offset Offset in buffer
193  * @param size   <size> parameter
194  * @param data   <data> parameter
195  **/
196 void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
197                                          glw::GLvoid* data)
198 {
199         gl.bufferSubData(target, offset, size, data);
200         GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData");
201 }
202
203 /* Framebuffer constants */
204 const GLuint Framebuffer::m_invalid_id = -1;
205
206 /** Constructor.
207  *
208  * @param context CTS context.
209  **/
210 Framebuffer::Framebuffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
211 {
212         /* Nothing to done here */
213 }
214
215 /** Destructor
216  *
217  **/
218 Framebuffer::~Framebuffer()
219 {
220         Release();
221 }
222
223 /** Release texture instance
224  *
225  **/
226 void Framebuffer::Release()
227 {
228         if (m_invalid_id != m_id)
229         {
230                 m_gl.deleteFramebuffers(1, &m_id);
231                 m_id = m_invalid_id;
232         }
233 }
234
235 /** Attach texture to specified attachment
236  *
237  * @param gl         GL functions
238  * @param target     Framebuffer target
239  * @param attachment Attachment
240  * @param texture_id Texture id
241  * @param level      Level of mipmap
242  * @param width      Texture width
243  * @param height     Texture height
244  **/
245 void Framebuffer::AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
246                                                                 glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height)
247 {
248         gl.framebufferTexture(target, attachment, texture_id, level);
249         GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
250
251         gl.viewport(0 /* x */, 0 /* y */, width, height);
252         GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
253 }
254
255 /** Binds framebuffer to DRAW_FRAMEBUFFER
256  *
257  * @param gl     GL functions
258  * @param target Framebuffer target
259  * @param id     ID of framebuffer
260  **/
261 void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id)
262 {
263         gl.bindFramebuffer(target, id);
264         GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
265 }
266
267 /** Generate framebuffer
268  *
269  **/
270 void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
271 {
272         GLuint id = m_invalid_id;
273
274         gl.genFramebuffers(1, &id);
275         GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
276
277         if (m_invalid_id == id)
278         {
279                 TCU_FAIL("Invalid id");
280         }
281
282         out_id = id;
283 }
284
285 /* Program constants */
286 const GLuint Program::m_invalid_id = 0;
287
288 /** Constructor.
289  *
290  * @param context CTS context.
291  **/
292 Program::Program(const glw::Functions& gl)
293         : m_id(m_invalid_id)
294         , m_compute(gl)
295         , m_fragment(gl)
296         , m_geometry(gl)
297         , m_tess_ctrl(gl)
298         , m_tess_eval(gl)
299         , m_vertex(gl)
300         , m_gl(gl)
301 {
302         /* Nothing to be done here */
303 }
304
305 /** Destructor
306  *
307  **/
308 Program::~Program()
309 {
310         Release();
311 }
312
313 /** Initialize program instance
314  *
315  * @param compute_shader                Compute shader source code
316  * @param fragment_shader               Fragment shader source code
317  * @param geometry_shader               Geometry shader source code
318  * @param tesselation_control_shader    Tesselation control shader source code
319  * @param tesselation_evaluation_shader Tesselation evaluation shader source code
320  * @param vertex_shader                 Vertex shader source code
321  **/
322 void Program::Init(const std::string& compute_shader, const std::string& fragment_shader,
323                                    const std::string& geometry_shader, const std::string& tesselation_control_shader,
324                                    const std::string& tesselation_evaluation_shader, const std::string& vertex_shader)
325 {
326         /* Delete previous program */
327         Release();
328
329         /* Initialize shaders */
330         m_compute.Init(GL_COMPUTE_SHADER, compute_shader);
331         m_fragment.Init(GL_FRAGMENT_SHADER, fragment_shader);
332         m_geometry.Init(GL_GEOMETRY_SHADER, geometry_shader);
333         m_tess_ctrl.Init(GL_TESS_CONTROL_SHADER, tesselation_control_shader);
334         m_tess_eval.Init(GL_TESS_EVALUATION_SHADER, tesselation_evaluation_shader);
335         m_vertex.Init(GL_VERTEX_SHADER, vertex_shader);
336
337         /* Create program, set up transform feedback and attach shaders */
338         Create(m_gl, m_id);
339         Attach(m_gl, m_id, m_compute.m_id);
340         Attach(m_gl, m_id, m_fragment.m_id);
341         Attach(m_gl, m_id, m_geometry.m_id);
342         Attach(m_gl, m_id, m_tess_ctrl.m_id);
343         Attach(m_gl, m_id, m_tess_eval.m_id);
344         Attach(m_gl, m_id, m_vertex.m_id);
345
346         /* Link program */
347         Link(m_gl, m_id);
348 }
349
350 /** Release program instance
351  *
352  **/
353 void Program::Release()
354 {
355         if (m_invalid_id != m_id)
356         {
357                 Use(m_gl, m_invalid_id);
358
359                 m_gl.deleteProgram(m_id);
360                 m_id = m_invalid_id;
361         }
362
363         m_compute.Release();
364         m_fragment.Release();
365         m_geometry.Release();
366         m_tess_ctrl.Release();
367         m_tess_eval.Release();
368         m_vertex.Release();
369 }
370
371 /** Set program as active
372  *
373  **/
374 void Program::Use() const
375 {
376         Use(m_gl, m_id);
377 }
378
379 /** Attach shader to program
380  *
381  * @param gl         GL functions
382  * @param program_id Id of program
383  * @param shader_id  Id of shader
384  **/
385 void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id)
386 {
387         /* Sanity checks */
388         if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id))
389         {
390                 return;
391         }
392
393         gl.attachShader(program_id, shader_id);
394         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
395 }
396
397 /** Create program instance
398  *
399  * @param gl     GL functions
400  * @param out_id Id of program
401  **/
402 void Program::Create(const glw::Functions& gl, glw::GLuint& out_id)
403 {
404         const GLuint id = gl.createProgram();
405         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
406
407         if (m_invalid_id == id)
408         {
409                 TCU_FAIL("Failed to create program");
410         }
411
412         out_id = id;
413 }
414
415 /** Link program
416  *
417  * @param gl GL functions
418  * @param id Id of program
419  **/
420 void Program::Link(const glw::Functions& gl, glw::GLuint id)
421 {
422         GLint status = GL_FALSE;
423
424         gl.linkProgram(id);
425         GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
426
427         /* Get link status */
428         gl.getProgramiv(id, GL_LINK_STATUS, &status);
429         GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
430
431         /* Log link error */
432         if (GL_TRUE != status)
433         {
434                 glw::GLint  length = 0;
435                 std::string message;
436
437                 /* Get error log length */
438                 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
439                 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
440
441                 message.resize(length, 0);
442
443                 /* Get error log */
444                 gl.getProgramInfoLog(id, length, 0, &message[0]);
445                 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
446
447                 TCU_FAIL(message.c_str());
448         }
449 }
450
451 /** Use program
452  *
453  * @param gl GL functions
454  * @param id Id of program
455  **/
456 void Program::Use(const glw::Functions& gl, glw::GLuint id)
457 {
458         gl.useProgram(id);
459         GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
460 }
461
462 /* Shader's constants */
463 const GLuint Shader::m_invalid_id = 0;
464
465 /** Constructor.
466  *
467  * @param context CTS context.
468  **/
469 Shader::Shader(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
470 {
471         /* Nothing to be done here */
472 }
473
474 /** Destructor
475  *
476  **/
477 Shader::~Shader()
478 {
479         Release();
480 }
481
482 /** Initialize shader instance
483  *
484  * @param stage  Shader stage
485  * @param source Source code
486  **/
487 void Shader::Init(glw::GLenum stage, const std::string& source)
488 {
489         if (true == source.empty())
490         {
491                 /* No source == no shader */
492                 return;
493         }
494
495         /* Delete any previous shader */
496         Release();
497
498         Create(m_gl, stage, m_id);
499         Source(m_gl, m_id, source);
500
501         Compile(m_gl, m_id);
502 }
503
504 /** Release shader instance
505  *
506  **/
507 void Shader::Release()
508 {
509         if (m_invalid_id != m_id)
510         {
511                 m_gl.deleteShader(m_id);
512                 m_id = m_invalid_id;
513         }
514 }
515
516 /** Compile shader
517  *
518  * @param gl GL functions
519  * @param id Shader id
520  **/
521 void Shader::Compile(const glw::Functions& gl, glw::GLuint id)
522 {
523         GLint status = GL_FALSE;
524
525         /* Compile */
526         gl.compileShader(id);
527         GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
528
529         /* Get compilation status */
530         gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
531         GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
532
533         /* Log compilation error */
534         if (GL_TRUE != status)
535         {
536                 glw::GLint  length = 0;
537                 std::string message;
538
539                 /* Error log length */
540                 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
541                 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
542
543                 /* Prepare storage */
544                 message.resize(length, 0);
545
546                 /* Get error log */
547                 gl.getShaderInfoLog(id, length, 0, &message[0]);
548                 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
549
550                 TCU_FAIL(message.c_str());
551         }
552 }
553
554 /** Create shader
555  *
556  * @param gl     GL functions
557  * @param stage  Shader stage
558  * @param out_id Shader id
559  **/
560 void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id)
561 {
562         const GLuint id = gl.createShader(stage);
563         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
564
565         if (m_invalid_id == id)
566         {
567                 TCU_FAIL("Failed to create shader");
568         }
569
570         out_id = id;
571 }
572
573 /** Set shader's source code
574  *
575  * @param gl     GL functions
576  * @param id     Shader id
577  * @param source Shader source code
578  **/
579 void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source)
580 {
581         const GLchar* code = source.c_str();
582
583         gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
584         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
585 }
586
587 /* Texture static fields */
588 const GLuint Texture::m_invalid_id = -1;
589
590 /** Constructor.
591  *
592  * @param context CTS context.
593  **/
594 Texture::Texture(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
595 {
596         /* Nothing to done here */
597 }
598
599 /** Destructor
600  *
601  **/
602 Texture::~Texture()
603 {
604         Release();
605 }
606
607 /** Release texture instance
608  *
609  **/
610 void Texture::Release()
611 {
612         if (m_invalid_id != m_id)
613         {
614                 m_gl.deleteTextures(1, &m_id);
615                 m_id = m_invalid_id;
616         }
617 }
618
619 /** Bind texture to target
620  *
621  * @param gl       GL functions
622  * @param id       Id of texture
623  * @param tex_type Type of texture
624  **/
625 void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
626 {
627         gl.bindTexture(target, id);
628         GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
629 }
630
631 /** Set contents of compressed texture
632  *
633  * @param gl              GL functions
634  * @param target          Texture target
635  * @param level           Mipmap level
636  * @param internal_format Format of data
637  * @param width           Width of texture
638  * @param height          Height of texture
639  * @param depth           Depth of texture
640  * @param image_size      Size of data
641  * @param data            Buffer with image data
642  **/
643 void Texture::CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
644                                                           glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
645                                                           glw::GLsizei image_size, const glw::GLvoid* data)
646 {
647         switch (target)
648         {
649         case GL_TEXTURE_1D:
650                 gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data);
651                 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D");
652                 break;
653         case GL_TEXTURE_1D_ARRAY:
654         case GL_TEXTURE_2D:
655         case GL_TEXTURE_RECTANGLE:
656                 gl.compressedTexImage2D(target, level, internal_format, width, height, 0 /* border */, image_size, data);
657                 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
658                 break;
659         case GL_TEXTURE_CUBE_MAP:
660                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */,
661                                                                 image_size, data);
662                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */,
663                                                                 image_size, data);
664                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */,
665                                                                 image_size, data);
666                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */,
667                                                                 image_size, data);
668                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */,
669                                                                 image_size, data);
670                 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */,
671                                                                 image_size, data);
672                 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
673                 break;
674         case GL_TEXTURE_3D:
675         case GL_TEXTURE_2D_ARRAY:
676                 gl.compressedTexImage3D(target, level, internal_format, width, height, depth, 0 /* border */, image_size, data);
677                 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage3D");
678                 break;
679         default:
680                 TCU_FAIL("Invliad enum");
681                 break;
682         }
683 }
684
685 /** Generate texture instance
686  *
687  * @param gl     GL functions
688  * @param out_id Id of texture
689  **/
690 void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id)
691 {
692         GLuint id = m_invalid_id;
693
694         gl.genTextures(1, &id);
695         GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
696
697         if (m_invalid_id == id)
698         {
699                 TCU_FAIL("Invalid id");
700         }
701
702         out_id = id;
703 }
704
705 /** Get texture data
706  *
707  * @param gl       GL functions
708  * @param target   Texture target
709  * @param format   Format of data
710  * @param type     Type of data
711  * @param out_data Buffer for data
712  **/
713 void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
714                                           glw::GLenum type, glw::GLvoid* out_data)
715 {
716         gl.getTexImage(target, level, format, type, out_data);
717         GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
718 }
719
720 /** Get texture data
721  *
722  * @param gl       GL functions
723  * @param id       Texture id
724  * @param level    Mipmap level
725  * @param width    Texture width
726  * @param height   Texture height
727  * @param format   Format of data
728  * @param type     Type of data
729  * @param out_data Buffer for data
730  **/
731 void Texture::GetData(const glw::Functions& gl, glw::GLuint id, glw::GLint level, glw::GLuint width, glw::GLuint height,
732                                           glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
733 {
734         GLuint fbo;
735         gl.genFramebuffers(1, &fbo);
736         GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
737         gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
738         GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
739         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, level);
740         GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
741
742         gl.readPixels(0, 0, width, height, format, type, out_data);
743         GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
744
745         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
746 }
747
748 /** Generate texture instance
749  *
750  * @param gl     GL functions
751  * @param target Texture target
752  * @param level  Mipmap level
753  * @param pname  Parameter to query
754  * @param param  Result of query
755  **/
756 void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
757                                                                 glw::GLint* param)
758 {
759         gl.getTexLevelParameteriv(target, level, pname, param);
760         GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv");
761 }
762
763 /** Set contents of texture
764  *
765  * @param gl              GL functions
766  * @param target          Texture target
767  * @param level           Mipmap level
768  * @param internal_format Format of data
769  * @param width           Width of texture
770  * @param height          Height of texture
771  * @param depth           Depth of texture
772  * @param format          Format of data
773  * @param type            Type of data
774  * @param data            Buffer with image data
775  **/
776 void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
777                                         glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
778                                         const glw::GLvoid* data)
779 {
780         switch (target)
781         {
782         case GL_TEXTURE_1D:
783                 gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data);
784                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D");
785                 break;
786         case GL_TEXTURE_1D_ARRAY:
787         case GL_TEXTURE_2D:
788         case GL_TEXTURE_RECTANGLE:
789                 gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
790                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
791                 break;
792         case GL_TEXTURE_CUBE_MAP:
793                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format,
794                                           type, data);
795                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format,
796                                           type, data);
797                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format,
798                                           type, data);
799                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format,
800                                           type, data);
801                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format,
802                                           type, data);
803                 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format,
804                                           type, data);
805                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
806                 break;
807         case GL_TEXTURE_3D:
808         case GL_TEXTURE_2D_ARRAY:
809                 gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
810                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D");
811                 break;
812         default:
813                 TCU_FAIL("Invliad enum");
814                 break;
815         }
816 }
817
818 /** Allocate storage for texture
819  *
820  * @param gl              GL functions
821  * @param target          Texture target
822  * @param levels          Number of levels
823  * @param internal_format Internal format of texture
824  * @param width           Width of texture
825  * @param height          Height of texture
826  * @param depth           Depth of texture
827  **/
828 void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
829                                           glw::GLuint width, glw::GLuint height, glw::GLuint depth)
830 {
831         switch (target)
832         {
833         case GL_TEXTURE_1D:
834                 gl.texStorage1D(target, levels, internal_format, width);
835                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D");
836                 break;
837         case GL_TEXTURE_1D_ARRAY:
838         case GL_TEXTURE_2D:
839         case GL_TEXTURE_RECTANGLE:
840         case GL_TEXTURE_CUBE_MAP:
841                 gl.texStorage2D(target, levels, internal_format, width, height);
842                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
843                 break;
844         case GL_TEXTURE_2D_MULTISAMPLE:
845                 gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
846                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
847                 break;
848         case GL_TEXTURE_3D:
849         case GL_TEXTURE_2D_ARRAY:
850                 gl.texStorage3D(target, levels, internal_format, width, height, depth);
851                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
852                 break;
853         default:
854                 TCU_FAIL("Invliad enum");
855                 break;
856         }
857 }
858
859 /** Set contents of texture
860  *
861  * @param gl              GL functions
862  * @param target          Texture target
863  * @param level           Mipmap level
864  * @param x               X offset
865  * @param y               Y offset
866  * @param z               Z offset
867  * @param width           Width of texture
868  * @param height          Height of texture
869  * @param depth           Depth of texture
870  * @param format          Format of data
871  * @param type            Type of data
872  * @param pixels          Buffer with image data
873  **/
874 void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
875                                            glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
876                                            glw::GLenum type, const glw::GLvoid* pixels)
877 {
878         switch (target)
879         {
880         case GL_TEXTURE_1D:
881                 gl.texSubImage1D(target, level, x, width, format, type, pixels);
882                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D");
883                 break;
884         case GL_TEXTURE_1D_ARRAY:
885         case GL_TEXTURE_2D:
886         case GL_TEXTURE_RECTANGLE:
887                 gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
888                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
889                 break;
890         case GL_TEXTURE_CUBE_MAP:
891                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels);
892                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels);
893                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels);
894                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels);
895                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels);
896                 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels);
897                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
898                 break;
899         case GL_TEXTURE_3D:
900         case GL_TEXTURE_2D_ARRAY:
901                 gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
902                 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
903                 break;
904         default:
905                 TCU_FAIL("Invliad enum");
906                 break;
907         }
908 }
909
910 /* VertexArray constants */
911 const GLuint VertexArray::m_invalid_id = -1;
912
913 /** Constructor.
914  *
915  * @param context CTS context.
916  **/
917 VertexArray::VertexArray(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
918 {
919 }
920
921 /** Destructor
922  *
923  **/
924 VertexArray::~VertexArray()
925 {
926         Release();
927 }
928
929 /** Release vertex array object instance
930  *
931  **/
932 void VertexArray::Release()
933 {
934         if (m_invalid_id != m_id)
935         {
936                 Bind(m_gl, 0);
937
938                 m_gl.deleteVertexArrays(1, &m_id);
939
940                 m_id = m_invalid_id;
941         }
942 }
943
944 /** Binds Vertex array object
945  *
946  * @param gl GL functions
947  * @param id ID of vertex array object
948  **/
949 void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id)
950 {
951         gl.bindVertexArray(id);
952         GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
953 }
954
955 /** Generates Vertex array object
956  *
957  * @param gl     GL functions
958  * @param out_id ID of vertex array object
959  **/
960 void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id)
961 {
962         GLuint id = m_invalid_id;
963
964         gl.genVertexArrays(1, &id);
965         GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
966
967         if (m_invalid_id == id)
968         {
969                 TCU_FAIL("Invalid id");
970         }
971
972         out_id = id;
973 }
974
975 template <typename TYPE>
976 void initPixels(std::vector<TYPE>& pixels, GLuint n_pixels, GLuint n_channels)
977 {
978         if (n_channels == 1)
979         {
980                 for (GLuint i = 0; i < n_pixels; ++i)
981                         pixels[i] = static_cast<TYPE>(i);
982         }
983         else if (n_channels == 2)
984         {
985                 for (GLuint i = 0; i < n_pixels; ++i)
986                 {
987                         GLuint idx              = i * 2;
988                         pixels[idx]             = static_cast<TYPE>(i);
989                         pixels[idx + 1] = pixels[idx];
990                 }
991         }
992         else if (n_channels == 4)
993         {
994                 for (GLuint i = 0; i < n_pixels; ++i)
995                 {
996                         GLuint idx              = i * 4;
997                         pixels[idx]             = static_cast<TYPE>(i);
998                         pixels[idx + 1] = pixels[idx];
999                         pixels[idx + 2] = pixels[idx];
1000                         pixels[idx + 3] = pixels[idx];
1001                 }
1002         }
1003         else
1004                 TCU_FAIL("Unsuported number of channels");
1005 }
1006
1007 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description,
1008                                                            glu::ApiType apiType)
1009         : tcu::TestCase(testCtx, name, description), m_api_type(apiType), m_has_khr_robust_buffer_access(false)
1010 {
1011 }
1012
1013 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
1014 {
1015         // Create test context to verify if required extensions are available
1016         {
1017                 deqp::Context                   context(m_testCtx, glu::ContextType(m_api_type));
1018                 const glu::ContextInfo& contextInfo  = context.getContextInfo();
1019                 glu::ContextType                context_type = context.getRenderContext().getType();
1020                 if (!contextInfo.isExtensionSupported("GL_KHR_robustness") &&
1021                         !contextSupports(context_type, glu::ApiType::es(3, 2)))
1022                 {
1023                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_robustness extension not supported");
1024                         return NULL;
1025                 }
1026
1027                 m_has_khr_robust_buffer_access = contextInfo.isExtensionSupported("GL_KHR_robust_buffer_access_behavior") ||
1028                                                                                  contextInfo.isExtensionSupported("GL_ARB_robust_buffer_access_behavior") ||
1029                                                                                  contextSupports(context_type, glu::ApiType::core(4, 5));
1030                 if (!m_has_khr_robust_buffer_access && !contextSupports(context_type, glu::ApiType::core(4, 3)))
1031                 {
1032                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
1033                                                                         "robust_buffer_access_behavior extension not supported");
1034                         return NULL;
1035                 }
1036
1037                 glu::GLSLVersion glslVersion   = glu::getContextTypeGLSLVersion(context_type);
1038                 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
1039                 m_context_is_es                            = glu::isContextTypeES(context_type);
1040         }
1041
1042         glu::RenderConfig               renderCfg(glu::ContextType(m_api_type, glu::CONTEXT_ROBUST));
1043         const tcu::CommandLine& commandLine = m_testCtx.getCommandLine();
1044         glu::parseRenderConfig(&renderCfg, commandLine);
1045
1046         if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW)
1047                 renderCfg.resetNotificationStrategy = reset;
1048         else
1049                 throw tcu::NotSupportedError("Test not supported in non-windowed context");
1050
1051         /* Try to create core/es robusness context */
1052         return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg);
1053 }
1054
1055 /** Constructor
1056  *
1057  * @param testCtx Test context
1058  **/
1059 VertexBufferObjectsTest::VertexBufferObjectsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1060         : RobustnessBase(testCtx, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero",
1061                                          apiType)
1062 {
1063         /* Nothing to be done */
1064 }
1065
1066 /** Execute test
1067  *
1068  * @return tcu::TestNode::STOP
1069  **/
1070 tcu::TestNode::IterateResult VertexBufferObjectsTest::iterate()
1071 {
1072         de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1073         if (!robustContext.get())
1074                 return STOP;
1075
1076         static const GLuint invalid_elements[] = {
1077                 9, 1, 12, 10, 2, 3, 11, 3, 4, 12, 4, 5, 13, 5, 6, 14, 6, 7, 15, 7, 8, 16, 8, 1,
1078         };
1079
1080         static const GLuint valid_elements[] = {
1081                 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
1082         };
1083
1084         static const GLfloat vertices[] = {
1085                 0.0f,  0.0f,  0.0f, /* 0 */
1086                 -1.0f, 0.0f,  0.0f, /* 1 */
1087                 -1.0f, 1.0f,  0.0f, /* 2 */
1088                 0.0f,  1.0f,  0.0f, /* 3 */
1089                 1.0f,  1.0f,  0.0f, /* 4 */
1090                 1.0f,  0.0f,  0.0f, /* 5 */
1091                 1.0f,  -1.0f, 0.0f, /* 6 */
1092                 0.0f,  -1.0f, 0.0f, /* 7 */
1093                 -1.0f, -1.0f, 0.0f, /* 8 */
1094         };
1095
1096         static const GLuint height       = 8;
1097         static const GLuint n_vertices = 24;
1098         static const GLuint width         = 8;
1099
1100         /* GL entry points */
1101         const Functions& gl = robustContext->getFunctions();
1102
1103         /* Test case objects */
1104         Framebuffer framebuffer(gl);
1105         Program         program(gl);
1106         Texture         texture(gl);
1107         Buffer          elements_buffer(gl);
1108         Buffer          vertices_buffer(gl);
1109         VertexArray vao(gl);
1110
1111         /* Vertex array */
1112         VertexArray::Generate(gl, vao.m_id);
1113         VertexArray::Bind(gl, vao.m_id);
1114
1115         /* Buffers initialization */
1116         elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(valid_elements), valid_elements);
1117         vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
1118
1119         /* Texture initialization */
1120         Texture::Generate(gl, texture.m_id);
1121         Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
1122         Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
1123         Texture::Bind(gl, 0, GL_TEXTURE_2D);
1124
1125         /* Framebuffer initialization*/
1126         Framebuffer::Generate(gl, framebuffer.m_id);
1127         Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1128         Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width,
1129                                                            height);
1130
1131         /* Shaders initialization */
1132         program.Init("" /* cs */, getFragmentShader(), "" /* gs */, "" /* tcs */, "" /* tes */, getVertexShader());
1133         Program::Use(gl, program.m_id);
1134
1135         /* Vertex buffer initialization */
1136         vertices_buffer.Bind();
1137         gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 12 /* stride */);
1138         gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, NULL);
1139         gl.enableVertexAttribArray(0 /* location */);
1140
1141         /* Binding elements/indices buffer */
1142         elements_buffer.Bind();
1143
1144         cleanTexture(gl, texture.m_id);
1145
1146         gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1147         GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1148
1149         if (false == verifyValidResults(gl, texture.m_id))
1150         {
1151                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for valid input" << tcu::TestLog::EndMessage;
1152
1153                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1154                 return tcu::TestNode::STOP;
1155         }
1156
1157         /* Generate invalid data sets */
1158         const GLuint invalid_elements_offsets[] = {
1159                 0,                               // close fetch
1160                 4 * 1024,                // near fetch (4K of the end of the object)
1161                 1024 * 1024,     // medium fetch (1MB past the end of the object)
1162                 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
1163         };
1164         const GLuint invalid_buffers_count = DE_LENGTH_OF_ARRAY(invalid_elements_offsets);
1165         const GLuint item_count                    = DE_LENGTH_OF_ARRAY(invalid_elements);
1166         GLuint           invalid_elements_set[invalid_buffers_count][item_count];
1167         for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1168         {
1169                 for (GLuint item_index = 0; item_index < item_count; ++item_index)
1170                         invalid_elements_set[buffer_index][item_index] =
1171                                 invalid_elements[item_index] + invalid_elements_offsets[buffer_index];
1172         }
1173
1174         for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1175         {
1176                 /* Create elements/indices buffer */
1177                 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(invalid_elements_set[buffer_index]),
1178                                                                  invalid_elements_set[buffer_index]);
1179                 elements_buffer.Bind();
1180
1181                 cleanTexture(gl, texture.m_id);
1182
1183                 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1184                 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1185
1186                 if (false == verifyInvalidResults(gl, texture.m_id))
1187                 {
1188                         m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for invalid input"
1189                                                            << tcu::TestLog::EndMessage;
1190                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1191                         return tcu::TestNode::STOP;
1192                 }
1193         }
1194
1195         /* Done */
1196         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1197         return tcu::TestNode::STOP;
1198 }
1199
1200 /** Prepare shader for current test case
1201  *
1202  * @return Source
1203  **/
1204 std::string VertexBufferObjectsTest::getFragmentShader()
1205 {
1206         const char* source = "${VERSION}\n"
1207                                                  "layout (location = 0) out lowp uvec4 out_fs_color;\n"
1208                                                  "void main()\n"
1209                                                  "{\n"
1210                                                  "    out_fs_color = uvec4(1, 255, 255, 255);\n"
1211                                                  "}\n";
1212         return tcu::StringTemplate(source).specialize(m_specializationMap);
1213 }
1214
1215 /** Prepare shader for current test case
1216  *
1217  * @return Source
1218  **/
1219 std::string VertexBufferObjectsTest::getVertexShader()
1220 {
1221         const char* source = "${VERSION}\n"
1222                                                  "layout (location = 0) in vec4 in_vs_position;\n"
1223                                                  "void main()\n"
1224                                                  "{\n"
1225                                                  "    gl_Position = in_vs_position;\n"
1226                                                  "}\n";
1227
1228         return tcu::StringTemplate(source).specialize(m_specializationMap);
1229 }
1230
1231 /** Fill texture with value 128
1232  *
1233  * @param texture_id Id of texture
1234  **/
1235 void VertexBufferObjectsTest::cleanTexture(const Functions& gl, glw::GLuint texture_id)
1236 {
1237         static const GLuint height = 8;
1238         static const GLuint width  = 8;
1239
1240         GLubyte pixels[width * height];
1241         for (GLuint i = 0; i < width * height; ++i)
1242         {
1243                 pixels[i] = 128;
1244         }
1245
1246         Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1247
1248         Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level  */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
1249                                           GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
1250
1251         /* Unbind */
1252         Texture::Bind(gl, 0, GL_TEXTURE_2D);
1253 }
1254
1255 /** Verifies that texutre is not filled with 1
1256  *
1257  * @param texture_id Id of texture
1258  *
1259  * @return false when image is filled with 1, true otherwise
1260  **/
1261 bool VertexBufferObjectsTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1262 {
1263         // In OpenGL ES there is undefined out-of-bound behavior - no verification
1264         if (m_context_is_es)
1265                 return true;
1266         return !verifyResults(gl, texture_id);
1267 }
1268
1269 /** Verifies that texutre is filled with 1
1270  *
1271  * @param texture_id Id of texture
1272  *
1273  * @return true when image is filled with 1, false otherwise
1274  **/
1275 bool VertexBufferObjectsTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
1276 {
1277         return verifyResults(gl, texture_id);
1278 }
1279
1280 /** Verifies that texutre is filled with 1
1281  *
1282  * @param texture_id Id of texture
1283  *
1284  * @return true when image is filled with 1, false otherwise
1285  **/
1286 bool VertexBufferObjectsTest::verifyResults(const Functions& gl, glw::GLuint texture_id)
1287 {
1288         static const GLuint height = 8;
1289         static const GLuint width  = 8;
1290         GLuint                          pixel_size       = 4 * sizeof(GLuint);
1291         GLuint                          expected_value = 1;
1292
1293         std::vector<GLubyte> pixels(width * height * pixel_size, 0);
1294         Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1295         Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1296         Texture::Bind(gl, 0, GL_TEXTURE_2D);
1297
1298         /* Verify */
1299         for (GLuint i = 0; i < pixels.size(); i += pixel_size)
1300         {
1301                 if (expected_value != pixels[i])
1302                         return false;
1303         }
1304
1305         return true;
1306 }
1307
1308 /** Constructor
1309  *
1310  * @param testCtx Test context
1311  **/
1312 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1313         : RobustnessBase(testCtx, "texel_fetch", "Verifies that out-of-bound fetches from texture result in zero", apiType)
1314         , m_test_case(R8)
1315 {
1316         /* Nothing to be done */
1317 }
1318
1319 /** Constructor
1320  *
1321  * @param testCtx Test context
1322  * @param name Test name
1323  * @param description Test description
1324  * @param apiType Api type
1325  **/
1326 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, const char* name, const char* description,
1327                                                            glu::ApiType apiType)
1328         : RobustnessBase(testCtx, name, description, apiType), m_test_case(R8)
1329 {
1330         /* Nothing to be done */
1331 }
1332
1333 /** Execute test
1334  *
1335  * @return tcu::TestNode::STOP
1336  **/
1337 tcu::TestNode::IterateResult TexelFetchTest::iterate()
1338 {
1339         de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1340         if (!robustContext.get())
1341                 return STOP;
1342
1343         /* Constants */
1344         static const GLuint height = 16;
1345         static const GLuint width  = 16;
1346
1347         /* GL entry points */
1348         const Functions& gl = robustContext->getFunctions();
1349
1350         /* Test result indicator */
1351         bool test_result = true;
1352
1353         GLuint invalid_fetch_offsets[] = {
1354                 16,   // near fetch
1355                 512,  // medium fetch
1356                 1008, // high fetch
1357         };
1358         GLuint fetch_offsets_count = sizeof(invalid_fetch_offsets) / sizeof(GLuint);
1359         glu::ContextType contextType             = robustContext->getType();
1360
1361         /* Iterate over all cases */
1362         for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
1363         {
1364                 GLint  level              = 0;
1365                 GLenum texture_target = GL_TEXTURE_2D;
1366
1367                 if (R32UI_MULTISAMPLE == m_test_case || RG8_SNORM == m_test_case)
1368                 {
1369                         // 1. RG8_SNORM case:
1370                         // Skip RG8_SNORM format case.
1371                         // RG8_SNORM is not required to be used as a render target
1372                         // OpenGL 4.5 Core Spec, Page 197
1373                         //
1374                         // 2. R32UI_MULTISAMPLE case
1375                         // Skip test in multi sample case
1376                         // texelFetch with invalid lod plane results undefined value
1377                         // OpenGL 4.5 Core Spec, around page 377
1378                         m_test_case = (TEST_CASES)((GLuint)m_test_case + 1);
1379                         continue;
1380                 }
1381
1382                 /* */
1383                 Texture         destination_texture(gl);
1384                 Framebuffer framebuffer(gl);
1385                 Texture         source_texture(gl);
1386                 Program         program(gl);
1387                 VertexArray vao(gl);
1388
1389                 /* Prepare VAO */
1390                 VertexArray::Generate(gl, vao.m_id);
1391                 VertexArray::Bind(gl, vao.m_id);
1392
1393                 /* Prepare textures */
1394                 Texture::Generate(gl, destination_texture.m_id);
1395                 Texture::Generate(gl, source_texture.m_id);
1396
1397                 if (R32UI_MULTISAMPLE == m_test_case)
1398                 {
1399                         GLint max_integer_samples;
1400                         gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples);
1401                         GLint max_image_samples;
1402                         gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
1403                         if (max_integer_samples < 4 || max_image_samples < 4)
1404                         {
1405                                 /* prepareTexture() hard-codes 4 samples (n_levels) for
1406                                  * R32UI_MULTISAMPLE case. This value exceeds the required
1407                                  * min-max value (1 in OpenGL ES 3.2) and is not supported
1408                                  * by all implementations.
1409                                  *
1410                                  * Also, the test uses a compute shader with images
1411                                  * to upload the texture so max_image_samples >= 4
1412                                  * is also required.
1413                                  */
1414                                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1415                                                                    << tcu::TestLog::EndMessage;
1416
1417                                 continue;
1418                         }
1419                 }
1420
1421                 prepareTexture(gl, false, destination_texture.m_id);
1422                 prepareTexture(gl, true, source_texture.m_id);
1423
1424                 /* Select FBO settings */
1425                 if (R32UI_MIPMAP == m_test_case)
1426                 {
1427                         level = 1;
1428                 }
1429                 else if (R32UI_MULTISAMPLE == m_test_case)
1430                 {
1431                         texture_target = GL_TEXTURE_2D_MULTISAMPLE;
1432                 }
1433
1434                 /* Prepare FBO */
1435                 Framebuffer::Generate(gl, framebuffer.m_id);
1436                 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1437                 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destination_texture.m_id, level,
1438                                                                    width, height);
1439
1440                 /* Prepare valid program */
1441                 program.Init("" /* cs */, getFragmentShader(contextType, true), getGeometryShader(), "" /* tcs */, "" /* tes */,
1442                                          getVertexShader());
1443
1444                 /* Test valid case */
1445                 /* Set program */
1446                 Program::Use(gl, program.m_id);
1447
1448                 /* Set texture */
1449                 gl.activeTexture(GL_TEXTURE0); /* location = 0 */
1450                 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
1451                 Texture::Bind(gl, source_texture.m_id, texture_target);
1452                 gl.uniform1i(0 /* location */, 0 /* texture unit */);
1453                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1454
1455                 /* Check if setup is supported */
1456                 GLenum fbo_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1457                 GLU_EXPECT_NO_ERROR(gl.getError(), "CheckFramebufferStatus");
1458                 if (GL_FRAMEBUFFER_COMPLETE != fbo_status)
1459                 {
1460                         m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1461                                                            << tcu::TestLog::EndMessage;
1462
1463                         continue;
1464                 }
1465
1466                 /* Enable multisampling */
1467                 if (R32UI_MULTISAMPLE == m_test_case)
1468                 {
1469                         gl.enable(GL_MULTISAMPLE);
1470                         GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
1471                 }
1472
1473                 /* Draw */
1474                 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1475                 {
1476                         /* Get error from draw */
1477                         GLenum error = gl.getError();
1478
1479                         /* Disable multisampling */
1480                         if (R32UI_MULTISAMPLE == m_test_case)
1481                         {
1482                                 gl.disable(GL_MULTISAMPLE);
1483                                 GLU_EXPECT_NO_ERROR(gl.getError(), "Disable");
1484                         }
1485
1486                         /* Handle error from draw */
1487                         GLU_EXPECT_NO_ERROR(error, "DrawArrays");
1488                 }
1489
1490                 /* Verification */
1491                 if (false == verifyValidResults(gl, destination_texture.m_id))
1492                 {
1493                         test_result = false;
1494                 }
1495
1496                 /* Test invalid cases */
1497                 for (GLuint index = 0; index < fetch_offsets_count; ++index)
1498                 {
1499                         /* Prepare invalid program */
1500                         program.Init("" /* cs */, getFragmentShader(contextType, false, invalid_fetch_offsets[index]),
1501                                                  getGeometryShader(), "" /* tcs */, "" /* tes */, getVertexShader());
1502                         Program::Use(gl, program.m_id);
1503                         Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1504
1505                         /* Set texture */
1506                         gl.activeTexture(GL_TEXTURE0); /* location = 0 */
1507                         GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
1508                         Texture::Bind(gl, source_texture.m_id, texture_target);
1509                         gl.uniform1i(0 /* location */, 0 /* texture unit */);
1510                         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1511
1512                         /* Draw */
1513                         gl.clear(GL_COLOR_BUFFER_BIT);
1514                         gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1515                         GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
1516
1517                         /* Verification */
1518                         if (false == verifyInvalidResults(gl, destination_texture.m_id))
1519                         {
1520                                 test_result = false;
1521                                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed for "
1522                                                                    << invalid_fetch_offsets[index] << " offset" << tcu::TestLog::EndMessage;
1523                         }
1524                 }
1525         }
1526
1527         /* Set result */
1528         if (true == test_result)
1529         {
1530                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1531         }
1532         else
1533         {
1534                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1535         }
1536
1537         /* Done */
1538         return tcu::TestNode::STOP;
1539 }
1540
1541 /** Prepares source code for fragment shader
1542  *
1543  * @param is_case_valid Selects if valid or invalid case is tested
1544  *
1545  * @return string with prepared code
1546  **/
1547 std::string TexelFetchTest::getFragmentShader(const glu::ContextType&, bool is_case_valid, GLuint fetch_offset)
1548 {
1549         const GLchar* source = "${VERSION}\n"
1550                                                    "in lowp vec2 gs_fs_tex_coord;\n"
1551                                                    "layout (location = 0) out lowp ${TYPE} out_fs_color;\n"
1552                                                    "layout (location = 0) uniform lowp ${SAMPLER} uni_texture;\n"
1553                                                    "\n"
1554                                                    "void main()\n"
1555                                                    "{\n"
1556                                                    "  ivec2 point  = ivec2(gs_fs_tex_coord * 16.0 + float(${OFFSET}));\n"
1557                                                    "  out_fs_color = texelFetch(uni_texture, point, ${PLANE});\n"
1558                                                    "}\n";
1559
1560         m_specializationMap["PLANE"]   = "0";
1561         m_specializationMap["SAMPLER"] = "sampler2D";
1562         m_specializationMap["TYPE"]     = "vec4";
1563
1564         if (R32UI_MIPMAP == m_test_case)
1565         {
1566                 m_specializationMap["PLANE"]   = "1";
1567                 m_specializationMap["SAMPLER"] = "usampler2D";
1568                 m_specializationMap["TYPE"]     = "uvec4";
1569
1570                 if (false == is_case_valid)
1571                 {
1572                         fetch_offset = 0;
1573                         m_specializationMap["PLANE"] = "2";
1574                 }
1575         }
1576         else if (R32UI_MULTISAMPLE == m_test_case)
1577         {
1578                 m_specializationMap["PLANE"]   = "9";
1579                 m_specializationMap["SAMPLER"] = "usampler2DMS";
1580                 m_specializationMap["TYPE"]     = "uvec4";
1581
1582                 if (false == is_case_valid)
1583                 {
1584                         fetch_offset = 0;
1585                         m_specializationMap["PLANE"] = "gl_SampleID";
1586                 }
1587         }
1588
1589         std::stringstream offset;
1590         offset << fetch_offset;
1591         m_specializationMap["OFFSET"] = offset.str();
1592
1593         return tcu::StringTemplate(source).specialize(m_specializationMap);
1594 }
1595
1596 /** Prepare shader for current test case
1597  *
1598  * @return Source
1599  **/
1600 std::string TexelFetchTest::getGeometryShader()
1601 {
1602         static const GLchar* source = "${VERSION}\n"
1603                                                                   "layout(points)                           in;\n"
1604                                                                   "layout(triangle_strip, max_vertices = 4) out;\n"
1605                                                                   "\n"
1606                                                                   "out vec2 gs_fs_tex_coord;\n"
1607                                                                   "\n"
1608                                                                   "void main()\n"
1609                                                                   "{\n"
1610                                                                   "    gs_fs_tex_coord = vec2(0, 0);\n"
1611                                                                   "    gl_Position     = vec4(-1, -1, 0, 1);\n"
1612                                                                   "    EmitVertex();\n"
1613                                                                   "\n"
1614                                                                   "    gs_fs_tex_coord = vec2(0, 1);\n"
1615                                                                   "    gl_Position     = vec4(-1, 1, 0, 1);\n"
1616                                                                   "    EmitVertex();\n"
1617                                                                   "\n"
1618                                                                   "    gs_fs_tex_coord = vec2(1, 0);\n"
1619                                                                   "    gl_Position     = vec4(1, -1, 0, 1);\n"
1620                                                                   "    EmitVertex();\n"
1621                                                                   "\n"
1622                                                                   "    gs_fs_tex_coord = vec2(1, 1);\n"
1623                                                                   "    gl_Position     = vec4(1, 1, 0, 1);\n"
1624                                                                   "    EmitVertex();\n"
1625                                                                   "}\n";
1626
1627         return tcu::StringTemplate(source).specialize(m_specializationMap);
1628 }
1629
1630 /** Prepare shader for current test case
1631  *
1632  * @return Source
1633  **/
1634 std::string TexelFetchTest::getVertexShader()
1635 {
1636         static const GLchar* source = "${VERSION}\n"
1637                                                                   "\n"
1638                                                                   "void main()\n"
1639                                                                   "{\n"
1640                                                                   "    gl_Position = vec4(0, 0, 0, 1);\n"
1641                                                                   "}\n";
1642         return tcu::StringTemplate(source).specialize(m_specializationMap);
1643 }
1644
1645 /** Returns name of current test case
1646  *
1647  * @return Name of test case
1648  **/
1649 const glw::GLchar* TexelFetchTest::getTestCaseName() const
1650 {
1651         const GLchar* name = "";
1652
1653         switch (m_test_case)
1654         {
1655         case R8:
1656                 name = "Sampling GL_R8 texture";
1657                 break;
1658         case RG8_SNORM:
1659                 name = "Sampling GL_RG8_SNORM  texture";
1660                 break;
1661         case RGBA32F:
1662                 name = "Sampling GL_RGBA32F  texture";
1663                 break;
1664         case R32UI_MIPMAP:
1665                 name = "Sampling mipmap of GL_32UI texture";
1666                 break;
1667         case R32UI_MULTISAMPLE:
1668                 name = "Sampling GL_32UI multisampled texture";
1669                 break;
1670         default:
1671                 TCU_FAIL("Invalid enum");
1672                 break;
1673         }
1674
1675         return name;
1676 }
1677
1678 /** Prepare a texture
1679  *
1680  * @param is_source  Selects if texutre will be used as source or destination
1681  * @param texture_id Id of texutre
1682  **/
1683 void TexelFetchTest::prepareTexture(const Functions& gl, bool is_source, glw::GLuint texture_id)
1684 {
1685         /* Image size */
1686         static const GLuint image_height = 16;
1687         static const GLuint image_width  = 16;
1688
1689         /* Texture storage parameters */
1690         GLuint  height                  = image_height;
1691         GLenum  internal_format = 0;
1692         GLsizei n_levels                = 1;
1693         GLenum  target                  = GL_TEXTURE_2D;
1694         GLuint  width                   = image_width;
1695
1696         /* Prepare texture storage parameters */
1697         switch (m_test_case)
1698         {
1699         case R8:
1700                 internal_format = GL_R8;
1701                 break;
1702         case RG8_SNORM:
1703                 internal_format = GL_RG8_SNORM;
1704                 break;
1705         case RGBA32F:
1706                 internal_format = GL_RGBA32F;
1707                 break;
1708         case R32UI_MIPMAP:
1709                 height                  = 2 * image_height;
1710                 internal_format = GL_R32UI;
1711                 n_levels                = 2;
1712                 width                   = 2 * image_width;
1713                 break;
1714         case R32UI_MULTISAMPLE:
1715                 internal_format = GL_R32UI;
1716                 n_levels                = 4;
1717                 target                  = GL_TEXTURE_2D_MULTISAMPLE;
1718                 break;
1719         default:
1720                 TCU_FAIL("Invalid enum");
1721         }
1722
1723         /* Prepare storage */
1724         Texture::Bind(gl, texture_id, target);
1725         Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
1726
1727         /* Set samplers to NEAREST/NEAREST if required */
1728         if (R32UI_MULTISAMPLE != m_test_case)
1729         {
1730                 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1731                 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1732         }
1733
1734         /* Destination image can be left empty */
1735         if (false == is_source)
1736         {
1737                 Texture::Bind(gl, 0, target);
1738                 return;
1739         }
1740
1741         /* Prepare texture */
1742         if (R8 == m_test_case)
1743         {
1744                 GLubyte source_pixels[image_width * image_height];
1745                 for (GLuint i = 0; i < image_width * image_height; ++i)
1746                 {
1747                         source_pixels[i] = static_cast<GLubyte>(i);
1748                 }
1749
1750                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1751                                                   0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
1752         }
1753         else if (RG8_SNORM == m_test_case)
1754         {
1755                 static const GLuint n_components = 2;
1756
1757                 GLbyte source_pixels[image_width * image_height * n_components];
1758                 for (GLuint i = 0; i < image_width * image_height; ++i)
1759                 {
1760                         source_pixels[i * n_components + 0] = static_cast<GLubyte>((i % 16) - 8);
1761                         source_pixels[i * n_components + 1] = static_cast<GLubyte>((i / 16) - 8);
1762                 }
1763
1764                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1765                                                   0 /* depth */, GL_RG, GL_BYTE, source_pixels);
1766         }
1767         else if (RGBA32F == m_test_case)
1768         {
1769                 static const GLuint n_components = 4;
1770
1771                 GLfloat source_pixels[image_width * image_height * n_components];
1772                 for (GLuint i = 0; i < image_width * image_height; ++i)
1773                 {
1774                         source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
1775                         source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
1776                         source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
1777                         source_pixels[i * n_components + 3] = 1.0f;
1778                 }
1779
1780                 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1781                                                   0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
1782         }
1783         else if (R32UI_MIPMAP == m_test_case)
1784         {
1785                 GLuint source_pixels[image_width * image_height];
1786                 for (GLuint i = 0; i < image_width * image_height; ++i)
1787                 {
1788                         source_pixels[i] = i;
1789                 }
1790
1791                 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
1792                                                   0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
1793         }
1794         else if (R32UI_MULTISAMPLE == m_test_case)
1795         {
1796                 /* Compute shader */
1797                 static const GLchar* source =
1798                         "${VERSION}\n"
1799                         "\n"
1800                         "layout (local_size_x = ${LOCAL_SIZE}, local_size_y = ${LOCAL_SIZE}, local_size_z = 1) in;\n"
1801                         "layout (${QUALIFIER​S}) writeonly uniform highp uimage2DMS uni_image;\n"
1802                         "\n"
1803                         "void main()\n"
1804                         "{\n"
1805                         "    const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
1806                         "    const uint  index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
1807                         "\n"
1808                         "    imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
1809                         "    imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
1810                         "    imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
1811                         "    imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
1812                         "}\n"
1813                         "\n";
1814
1815                 if (m_context_is_es)
1816                 {
1817                         m_specializationMap["LOCAL_SIZE"]       = "16";
1818                         m_specializationMap["QUALIFIER​S"] = "binding = 0, r32ui";
1819                 }
1820                 else
1821                 {
1822                         m_specializationMap["LOCAL_SIZE"]       = "1";
1823                         m_specializationMap["QUALIFIER​S"] = "location = 0";
1824                 }
1825
1826                 Program         program(gl);
1827                 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
1828                 program.Init(cs, "", "", "", "", "");
1829                 program.Use();
1830
1831                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
1832                                                         GL_WRITE_ONLY, GL_R32UI);
1833                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1834
1835                 if (!m_context_is_es)
1836                 {
1837                         gl.uniform1i(0 /* location */, 0 /* image unit*/);
1838                         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1839                 }
1840
1841                 gl.dispatchCompute(16, 16, 1);
1842                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
1843         }
1844
1845         Texture::Bind(gl, 0, target);
1846 }
1847
1848 /** Verifies that texutre is filled with 0 or with (0, 0, 0, x),
1849  *  where x may be 0, 1 or the biggest representable integer value.
1850  *
1851  * @param texture_id Id of texture
1852  *
1853  * @return true when image is filled with 0, 1 or biggest represetable integer number, false otherwise
1854  **/
1855 bool TexelFetchTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1856 {
1857         static const GLuint height   = 16;
1858         static const GLuint width       = 16;
1859         static const GLuint n_pixels = height * width;
1860
1861         // OpenGL ES has undefined out-of-bound behavior - no verification
1862         if (m_context_is_es)
1863                 return true;
1864
1865         bool result = true;
1866
1867         if (R8 == m_test_case)
1868         {
1869                 static const GLuint n_channels = 4;
1870
1871                 std::vector<GLubyte> pixels(n_pixels * n_channels);
1872                 initPixels(pixels, n_pixels, n_channels);
1873
1874                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1875
1876                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
1877
1878                 /* Unbind */
1879                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1880
1881                 /* Verify */
1882                 for (GLuint i = 0; i < n_pixels; ++i)
1883                 {
1884                         const GLubyte expected_red = 0;
1885                         const GLubyte drawn_red = pixels[i * n_channels];
1886
1887                         if (expected_red != drawn_red)
1888                         {
1889                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
1890                                                                    << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
1891                                                                    << tcu::TestLog::EndMessage;
1892
1893                                 result = false;
1894                                 break;
1895                         }
1896                 }
1897         }
1898         else if (RG8_SNORM == m_test_case)
1899         {
1900                 static const GLuint n_channels = 4;
1901
1902                 std::vector<GLbyte> pixels(n_pixels * n_channels);
1903                 initPixels(pixels, n_pixels, n_channels);
1904
1905                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1906
1907                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_BYTE, &pixels[0]);
1908
1909                 /* Unbind */
1910                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1911
1912                 /* Verify */
1913                 for (GLuint i = 0; i < n_pixels; ++i)
1914                 {
1915                         const GLbyte expected_red   = 0;
1916                         const GLbyte expected_green = 0;
1917                         const GLbyte drawn_red          = pixels[i * n_channels + 0];
1918                         const GLbyte drawn_green        = pixels[i * n_channels + 1];
1919
1920                         if ((expected_red != drawn_red) || (expected_green != drawn_green))
1921                         {
1922                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
1923                                                                    << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
1924                                                                    << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
1925
1926                                 result = false;
1927                                 break;
1928                         }
1929                 }
1930         }
1931         else if (RGBA32F == m_test_case)
1932         {
1933                 static const GLuint n_channels = 4;
1934
1935                 std::vector<GLfloat> pixels(n_pixels * n_channels);
1936                 for (GLuint i = 0; i < n_pixels; ++i)
1937                 {
1938                         const GLuint  idx   = i * n_channels;
1939                         const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
1940                         pixels[idx + 0]         = value;
1941                         pixels[idx + 1]         = value;
1942                         pixels[idx + 2]         = value;
1943                         pixels[idx + 3]         = value;
1944                 }
1945
1946                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1947
1948                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
1949
1950                 /* Unbind */
1951                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1952
1953                 /* Verify */
1954                 for (GLuint i = 0; i < n_pixels; ++i)
1955                 {
1956                         const GLfloat expected_red   = 0.0f;
1957                         const GLfloat expected_green = 0.0f;
1958                         const GLfloat expected_blue  = 0.0f;
1959                         const GLfloat expected_alpha_0 =
1960                                 0.0f; /* OpenGL 4.5 (and ES) specifies two possiblities (0 or 1) for alpha channel (Chapter 11.1.3.12). */
1961                         const GLfloat expected_alpha_1 = 1.0f;
1962                         const GLfloat drawn_red            = pixels[i * n_channels + 0];
1963                         const GLfloat drawn_green         = pixels[i * n_channels + 1];
1964                         const GLfloat drawn_blue           = pixels[i * n_channels + 2];
1965                         const GLfloat drawn_alpha         = pixels[i * n_channels + 3];
1966
1967                         const GLfloat precision = 0.0009765625; /* (1.f / 1024.f) */
1968
1969                         if ((de::abs(expected_red - drawn_red) > precision) ||
1970                                 (de::abs(expected_green - drawn_green) > precision) ||
1971                                 (de::abs(expected_blue - drawn_blue) > precision) ||
1972                                 ((de::abs(expected_alpha_0 - drawn_alpha) > precision) &&
1973                                  (de::abs(expected_alpha_1 - drawn_alpha) > precision)))
1974                         {
1975                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
1976                                                                    << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
1977                                                                    << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha_0
1978                                                                    << " or " << expected_alpha_1 << ". At offset: " << i << tcu::TestLog::EndMessage;
1979
1980                                 result = false;
1981                                 break;
1982                         }
1983                 }
1984         }
1985         else if (R32UI_MIPMAP == m_test_case)
1986         {
1987                 static const GLuint n_channels = 4;
1988
1989                 std::vector<GLuint> pixels(n_pixels * n_channels);
1990                 initPixels(pixels, n_pixels, n_channels);
1991
1992                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1993
1994                 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1995
1996                 /* Unbind */
1997                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1998
1999                 /* Verify */
2000                 for (GLuint i = 0; i < n_pixels; ++i)
2001                 {
2002                         const GLuint expected_red = 0;
2003                         const GLuint drawn_red  = pixels[i * n_channels];
2004
2005                         if (expected_red != drawn_red)
2006                         {
2007                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2008                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2009                                                                    << tcu::TestLog::EndMessage;
2010
2011                                 result = false;
2012                                 break;
2013                         }
2014                 }
2015         }
2016         else if (R32UI_MULTISAMPLE == m_test_case)
2017         {
2018                 static const GLuint n_channels = 4;
2019
2020                 /* Compute shader */
2021                 static const GLchar* source =
2022                         "${VERSION}\n"
2023                         "\n"
2024                         "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2025                         "\n"
2026                         "layout (location = 1)        writeonly uniform uimage2D   uni_destination_image;\n"
2027                         "layout (location = 0, r32ui) readonly  uniform uimage2DMS uni_source_image;\n"
2028                         "\n"
2029                         "void main()\n"
2030                         "{\n"
2031                         "    const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2032                         "\n"
2033                         "    const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2034                         "    const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2035                         "    const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2036                         "    const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2037                         "\n"
2038                         "    if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2039                         "    {\n"
2040                         "        imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2041                         "    }\n"
2042                         "    else\n"
2043                         "    {\n"
2044                         "        imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2045                         "    }\n"
2046                         "}\n"
2047                         "\n";
2048
2049                 Program program(gl);
2050                 Texture destination_texture(gl);
2051
2052                 Texture::Generate(gl, destination_texture.m_id);
2053                 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2054                 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2055
2056                 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2057                 program.Init(cs, "", "", "", "", "");
2058                 program.Use();
2059                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2060                                                         GL_READ_ONLY, GL_R32UI);
2061                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2062                 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2063                                                         0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2064                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2065
2066                 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2067                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2068
2069                 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2070                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2071
2072                 gl.dispatchCompute(16, 16, 1);
2073                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2074
2075                 /* Pixels buffer initialization */
2076                 std::vector<GLuint> pixels(n_pixels * n_channels);
2077                 initPixels(pixels, n_pixels, n_channels);
2078
2079                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2080
2081                 /* Unbind */
2082                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2083
2084                 /* Verify */
2085                 for (GLuint i = 0; i < n_pixels; ++i)
2086                 {
2087                         const GLuint expected_red = 1;
2088                         const GLuint drawn_red  = pixels[i * n_channels];
2089
2090                         if (expected_red != drawn_red)
2091                         {
2092                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2093                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2094                                                                    << tcu::TestLog::EndMessage;
2095
2096                                 result = false;
2097                                 break;
2098                         }
2099                 }
2100         }
2101
2102         return result;
2103 }
2104
2105 /** Verifies that texutre is filled with increasing values
2106  *
2107  * @param texture_id Id of texture
2108  *
2109  * @return true when image is filled with increasing values, false otherwise
2110  **/
2111 bool TexelFetchTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
2112 {
2113         static const GLuint height   = 16;
2114         static const GLuint width       = 16;
2115         static const GLuint n_pixels = height * width;
2116
2117         bool result = true;
2118
2119         if (R8 == m_test_case)
2120         {
2121                 static const GLuint n_channels = 4;
2122
2123                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2124
2125                 std::vector<GLubyte> pixels(n_pixels * n_channels);
2126                 initPixels(pixels, n_pixels, n_channels);
2127
2128                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
2129
2130                 /* Unbind */
2131                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2132
2133                 /* Verify */
2134                 for (GLuint i = 0; i < n_pixels; ++i)
2135                 {
2136                         const GLubyte expected_red = static_cast<GLubyte>(i);
2137                         const GLubyte drawn_red = pixels[i * n_channels];
2138
2139                         if (expected_red != drawn_red)
2140                         {
2141                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2142                                                                    << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2143                                                                    << tcu::TestLog::EndMessage;
2144
2145                                 result = false;
2146                                 break;
2147                         }
2148                 }
2149         }
2150         else if (RG8_SNORM == m_test_case)
2151         {
2152                 static const GLuint n_channels = 4;
2153
2154                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2155
2156                 std::vector<GLbyte> pixels(n_pixels * n_channels);
2157                 initPixels(pixels, n_pixels, n_channels);
2158
2159                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
2160
2161                 /* Unbind */
2162                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2163
2164                 /* Verify */
2165                 for (GLuint i = 0; i < n_pixels; ++i)
2166                 {
2167                         const GLbyte expected_red   = static_cast<GLubyte>((i % 16) - 8);
2168                         const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
2169                         const GLbyte drawn_red          = pixels[i * n_channels + 0];
2170                         const GLbyte drawn_green        = pixels[i * n_channels + 1];
2171
2172                         if ((expected_red != drawn_red) || (expected_green != drawn_green))
2173                         {
2174                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2175                                                                    << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2176                                                                    << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2177
2178                                 result = false;
2179                                 break;
2180                         }
2181                 }
2182         }
2183         else if (RGBA32F == m_test_case)
2184         {
2185                 static const GLuint n_channels = 4;
2186
2187                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2188
2189                 std::vector<GLfloat> pixels(n_pixels * n_channels);
2190                 for (GLuint i = 0; i < n_pixels; ++i)
2191                 {
2192                         const GLuint  idx   = i * n_channels;
2193                         const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
2194                         pixels[idx + 0]         = value;
2195                         pixels[idx + 1]         = value;
2196                         pixels[idx + 2]         = value;
2197                         pixels[idx + 3]         = value;
2198                 }
2199
2200                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
2201
2202                 /* Unbind */
2203                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2204
2205                 /* Verify */
2206                 for (GLuint i = 0; i < n_pixels; ++i)
2207                 {
2208                         const GLfloat expected_red   = (GLfloat)(i % 16) / 16.0f;
2209                         const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
2210                         const GLfloat expected_blue  = (GLfloat)i / 256.0f;
2211                         const GLfloat expected_alpha = 1.0f;
2212                         const GLuint  idx                        = i * n_channels;
2213                         const GLfloat drawn_red          = pixels[idx + 0];
2214                         const GLfloat drawn_green       = pixels[idx + 1];
2215                         const GLfloat drawn_blue         = pixels[idx + 2];
2216                         const GLfloat drawn_alpha       = pixels[idx + 3];
2217
2218                         if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2219                                 (expected_alpha != drawn_alpha))
2220                         {
2221                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2222                                                                    << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2223                                                                    << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2224                                                                    << ". At offset: " << i << tcu::TestLog::EndMessage;
2225
2226                                 result = false;
2227                                 break;
2228                         }
2229                 }
2230         }
2231         else if (R32UI_MIPMAP == m_test_case)
2232         {
2233                 static const GLuint n_channels = 4;
2234
2235                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2236
2237                 std::vector<GLuint> pixels(n_pixels * n_channels, 0);
2238
2239                 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2240
2241                 /* Unbind */
2242                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2243
2244                 /* Verify */
2245                 for (GLuint i = 0; i < n_pixels; ++i)
2246                 {
2247                         const GLuint expected_red = i;
2248                         const GLuint drawn_red  = pixels[i * n_channels];
2249
2250                         if (expected_red != drawn_red)
2251                         {
2252                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2253                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2254                                                                    << tcu::TestLog::EndMessage;
2255
2256                                 result = false;
2257                                 break;
2258                         }
2259                 }
2260         }
2261         else if (R32UI_MULTISAMPLE == m_test_case)
2262         {
2263                 static const GLuint n_channels = 4;
2264
2265                 /* Compute shader */
2266                 static const GLchar* source =
2267                         "${VERSION}\n"
2268                         "\n"
2269                         "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2270                         "\n"
2271                         "layout (location = 1, r32ui) writeonly uniform uimage2D   uni_destination_image;\n"
2272                         "layout (location = 0, r32ui) readonly  uniform uimage2DMS uni_source_image;\n"
2273                         "\n"
2274                         "void main()\n"
2275                         "{\n"
2276                         "    const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2277                         "    const uint  index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
2278                         "\n"
2279                         "    const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2280                         "    const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2281                         "    const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2282                         "    const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2283                         "\n"
2284                         "    if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
2285                         "    {\n"
2286                         "        imageStore(uni_destination_image, point, uvec4(1U));\n"
2287                         "    }\n"
2288                         "    else\n"
2289                         "    {\n"
2290                         "        imageStore(uni_destination_image, point, uvec4(0U));\n"
2291                         "    }\n"
2292                         "}\n"
2293                         "\n";
2294
2295                 Program program(gl);
2296                 Texture destination_texture(gl);
2297
2298                 Texture::Generate(gl, destination_texture.m_id);
2299                 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2300                 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2301
2302                 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2303                 program.Init(cs, "", "", "", "", "");
2304                 program.Use();
2305                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2306                                                         GL_READ_ONLY, GL_R32UI);
2307                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2308                 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2309                                                         0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2310                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2311
2312                 if (!m_context_is_es)
2313                 {
2314                         gl.uniform1i(0 /* location */, 0 /* image unit*/);
2315                         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2316
2317                         gl.uniform1i(1 /* location */, 1 /* image unit*/);
2318                         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2319                 }
2320
2321                 gl.dispatchCompute(16, 16, 1);
2322                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2323
2324                 /* Pixels buffer initialization */
2325                 std::vector<GLuint> pixels(n_pixels * n_channels);
2326                 initPixels(pixels, n_pixels, n_channels);
2327
2328                 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2329                                                  &pixels[0]);
2330
2331                 /* Unbind */
2332                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2333
2334                 /* Verify */
2335                 for (GLuint i = 0; i < n_pixels; ++i)
2336                 {
2337                         const GLuint expected_red = 1;
2338                         const GLuint drawn_red  = pixels[i * n_channels];
2339
2340                         if (expected_red != drawn_red)
2341                         {
2342                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2343                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2344                                                                    << tcu::TestLog::EndMessage;
2345
2346                                 result = false;
2347                                 break;
2348                         }
2349                 }
2350         }
2351
2352         return result;
2353 }
2354
2355 /** Constructor
2356  *
2357  * @param testCtx Test context
2358  * @param apiType Api type
2359  **/
2360 ImageLoadStoreTest::ImageLoadStoreTest(tcu::TestContext& testCtx, glu::ApiType apiType)
2361         : TexelFetchTest(testCtx, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded",
2362                                          apiType)
2363 {
2364 }
2365
2366 /** Execute test
2367  *
2368  * @return tcu::TestNode::STOP
2369  **/
2370 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
2371 {
2372         de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
2373         if (!robustContext.get())
2374                 return STOP;
2375
2376         /* Constants */
2377         static const GLuint height = 16;
2378         static const GLuint width  = 16;
2379
2380         /* GL entry points */
2381         const Functions& gl = robustContext->getFunctions();
2382
2383         struct FetchingOffset
2384         {
2385                 GLuint coord_offset;
2386                 GLuint sample_offset;
2387         };
2388         const FetchingOffset fetching_offsets[] = {
2389                 { 16, 4 }, { 512, 4 }, { 1024, 8 }, { 2048, 8 },
2390         };
2391
2392         /* For ES start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported */
2393         if (m_context_is_es)
2394                 m_test_case = RGBA32F;
2395
2396         /* Test result indicator */
2397         bool test_result = true;
2398
2399         /* Iterate over all cases */
2400         for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
2401         {
2402                 /* Test case result indicator */
2403                 bool case_result = true;
2404
2405                 if (R32UI_MULTISAMPLE == m_test_case)
2406                 {
2407                         // Skip invalid program test in multi sample case
2408                         // texelFetch with invalid lod plane results undefined value
2409                         // OpenGL 4.5 Core Spec, around page 377
2410                         continue;
2411                 }
2412
2413                 /* Test case objects */
2414                 Texture destination_texture(gl);
2415                 Texture source_texture(gl);
2416                 Program program(gl);
2417
2418                 /* Prepare textures */
2419                 Texture::Generate(gl, destination_texture.m_id);
2420                 Texture::Generate(gl, source_texture.m_id);
2421
2422                 if (R32UI_MULTISAMPLE == m_test_case)
2423                 {
2424                         GLint max_integer_samples;
2425                         gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples);
2426                         GLint max_image_samples;
2427                         gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
2428                         if (max_integer_samples < 4 || max_image_samples < 4)
2429                         {
2430                                 /* prepareTexture() hard-codes 4 samples (n_levels) for
2431                                  * R32UI_MULTISAMPLE case. This value exceeds the required
2432                                  * min-max value (1 in OpenGL ES 3.2) and is not supported
2433                                  * by all implementations.
2434                                  *
2435                                  * Also, the test uses a compute shader with images
2436                                  * to upload the texture so max_image_samples >= 4
2437                                  * is also required.
2438                                  */
2439                                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
2440                                                                    << tcu::TestLog::EndMessage;
2441                                 continue;
2442                         }
2443                 }
2444
2445                 prepareTexture(gl, false, destination_texture.m_id);
2446                 prepareTexture(gl, true, source_texture.m_id);
2447
2448                 /* Test invalid source cases */
2449                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2450                 {
2451                         const FetchingOffset& fo = fetching_offsets[i];
2452                         const std::string&      cs = getComputeShader(SOURCE_INVALID, fo.coord_offset, fo.sample_offset);
2453                         program.Init(cs, "", "", "", "", "");
2454                         program.Use();
2455
2456                         /* Set texture */
2457                         setTextures(gl, destination_texture.m_id, source_texture.m_id);
2458
2459                         /* Dispatch */
2460                         gl.dispatchCompute(width, height, 1 /* depth */);
2461                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2462
2463                         /* Verification */
2464                         if (false == verifyInvalidResults(gl, destination_texture.m_id))
2465                         {
2466                                 case_result = false;
2467                         }
2468                 }
2469
2470                 /* Test valid case */
2471                 program.Init(getComputeShader(VALID), "", "", "", "", "");
2472                 program.Use();
2473
2474                 /* Set texture */
2475                 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2476
2477                 /* Dispatch */
2478                 gl.dispatchCompute(width, height, 1 /* depth */);
2479                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2480
2481                 /* Verification */
2482                 if (false == verifyValidResults(gl, destination_texture.m_id))
2483                 {
2484                         case_result = false;
2485                 }
2486
2487                 /* Test invalid destination cases */
2488                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2489                 {
2490                         const FetchingOffset& fo = fetching_offsets[i];
2491                         const std::string&      cs = getComputeShader(DESTINATION_INVALID, fo.coord_offset, fo.sample_offset);
2492                         program.Init(cs, "", "", "", "", "");
2493                         program.Use();
2494
2495                         /* Set texture */
2496                         setTextures(gl, destination_texture.m_id, source_texture.m_id);
2497
2498                         /* Dispatch */
2499                         gl.dispatchCompute(width, height, 1 /* depth */);
2500                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2501
2502                         /* Verification */
2503                         if (false == verifyValidResults(gl, destination_texture.m_id))
2504                         {
2505                                 case_result = false;
2506                         }
2507                 }
2508
2509                 /* Set test result */
2510                 if (false == case_result)
2511                 {
2512                         m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed"
2513                                                            << tcu::TestLog::EndMessage;
2514
2515                         test_result = false;
2516                 }
2517         }
2518
2519         /* Set result */
2520         if (true == test_result)
2521         {
2522                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2523         }
2524         else
2525         {
2526                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2527         }
2528
2529         /* Done */
2530         return tcu::TestNode::STOP;
2531 }
2532
2533 /** Prepare shader for current test case
2534  *
2535  * @param version Specify which version should be prepared
2536  *
2537  * @return Source
2538  **/
2539 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset, GLuint sample_offset)
2540 {
2541         static const GLchar* source =
2542                 "${VERSION}\n"
2543                 "\n"
2544                 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2545                 "\n"
2546                 "layout (${QUALIFIER} = 1, ${FORMAT}) writeonly uniform highp ${IMAGE} uni_destination_image;\n"
2547                 "layout (${QUALIFIER} = 0, ${FORMAT}) readonly  uniform highp ${IMAGE} uni_source_image;\n"
2548                 "\n"
2549                 "void main()\n"
2550                 "{\n"
2551                 "  ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(${DST_COORD_OFFSET}U);\n"
2552                 "  ivec2 point_source      = ivec2(gl_WorkGroupID.xy) + ivec2(${SRC_COORD_OFFSET}U);\n"
2553                 "\n"
2554                 "${COPY}"
2555                 "}\n";
2556
2557         static const GLchar* copy_multisampled =
2558                 "  ${TYPE} color_0 = imageLoad(uni_source_image, point_source, 0 + ${SRC_SAMPLE_OFFSET});\n"
2559                 "  ${TYPE} color_1 = imageLoad(uni_source_image, point_source, 1 + ${SRC_SAMPLE_OFFSET});\n"
2560                 "  ${TYPE} color_2 = imageLoad(uni_source_image, point_source, 2 + ${SRC_SAMPLE_OFFSET});\n"
2561                 "  ${TYPE} color_3 = imageLoad(uni_source_image, point_source, 3 + ${SRC_SAMPLE_OFFSET});\n"
2562                 "  imageStore(uni_destination_image, point_destination, 0 + ${DST_SAMPLE_OFFSET}, color_0);\n"
2563                 "  imageStore(uni_destination_image, point_destination, 1 + ${DST_SAMPLE_OFFSET}, color_1);\n"
2564                 "  imageStore(uni_destination_image, point_destination, 2 + ${DST_SAMPLE_OFFSET}, color_2);\n"
2565                 "  imageStore(uni_destination_image, point_destination, 3 + ${DST_SAMPLE_OFFSET}, color_3);\n";
2566
2567         static const GLchar* copy_regular = "  ${TYPE} color = imageLoad(uni_source_image, point_source);\n"
2568                                                                                 "  imageStore(uni_destination_image, point_destination, color);\n";
2569
2570         std::string src_coord_offset_str("0");
2571         std::string dst_coord_offset_str("0");
2572         std::string src_sample_offset_str("0");
2573         std::string dst_sample_offset_str("0");
2574
2575         std::stringstream coord_offset_stream;
2576         coord_offset_stream << coord_offset;
2577         std::stringstream sample_offset_stream;
2578         sample_offset_stream << sample_offset;
2579
2580         m_specializationMap["QUALIFIER"] = m_context_is_es ? "binding" : "location";
2581         m_specializationMap["IMAGE"]     = "image2D";
2582         m_specializationMap["TYPE"]              = "vec4";
2583         switch (m_test_case)
2584         {
2585         case R8:
2586                 m_specializationMap["FORMAT"] = "r8";
2587                 break;
2588         case RG8_SNORM:
2589                 m_specializationMap["FORMAT"] = "rg8_snorm";
2590                 break;
2591         case RGBA32F:
2592                 m_specializationMap["FORMAT"] = "rgba32f";
2593                 break;
2594         case R32UI_MIPMAP:
2595                 m_specializationMap["FORMAT"] = "r32ui";
2596                 m_specializationMap["IMAGE"]  = "uimage2D";
2597                 m_specializationMap["TYPE"]   = "uvec4";
2598                 break;
2599         case R32UI_MULTISAMPLE:
2600                 m_specializationMap["FORMAT"] = "r32ui";
2601                 m_specializationMap["IMAGE"]  = "uimage2DMS";
2602                 m_specializationMap["TYPE"]   = "uvec4";
2603                 break;
2604         default:
2605                 TCU_FAIL("Invalid enum");
2606         };
2607
2608         m_specializationMap["SRC_COORD_OFFSET"]  = "0";
2609         m_specializationMap["SRC_SAMPLE_OFFSET"] = "0";
2610         m_specializationMap["DST_COORD_OFFSET"]  = "0";
2611         m_specializationMap["DST_SAMPLE_OFFSET"] = "0";
2612
2613         if (version == SOURCE_INVALID)
2614         {
2615                 m_specializationMap["SRC_COORD_OFFSET"]  = coord_offset_stream.str();
2616                 m_specializationMap["SRC_SAMPLE_OFFSET"] = sample_offset_stream.str();
2617         }
2618         else if (version == DESTINATION_INVALID)
2619         {
2620                 m_specializationMap["DST_COORD_OFFSET"]  = coord_offset_stream.str();
2621                 m_specializationMap["DST_SAMPLE_OFFSET"] = sample_offset_stream.str();
2622         }
2623
2624         const GLchar* copy                      = (m_test_case == R32UI_MULTISAMPLE) ? copy_multisampled : copy_regular;
2625         m_specializationMap["COPY"] = tcu::StringTemplate(copy).specialize(m_specializationMap);
2626
2627         return tcu::StringTemplate(source).specialize(m_specializationMap);
2628 }
2629
2630 /** Set textures as images
2631  *
2632  * @param id_destination Id of texture used as destination
2633  * @param id_source      Id of texture used as source
2634  **/
2635 void ImageLoadStoreTest::setTextures(const Functions& gl, glw::GLuint id_destination, glw::GLuint id_source)
2636 {
2637         GLenum format = 0;
2638         GLint  level  = 0;
2639
2640         switch (m_test_case)
2641         {
2642         case R8:
2643                 format = GL_R8;
2644                 break;
2645         case RG8_SNORM:
2646                 format = GL_RG8_SNORM;
2647                 break;
2648         case RGBA32F:
2649                 format = GL_RGBA32F;
2650                 break;
2651         case R32UI_MIPMAP:
2652                 format = GL_R32UI;
2653                 level  = 1;
2654                 break;
2655         case R32UI_MULTISAMPLE:
2656                 format = GL_R32UI;
2657                 break;
2658         default:
2659                 TCU_FAIL("Invalid enum");
2660         }
2661
2662         gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
2663         GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2664
2665         gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
2666                                                 format);
2667         GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2668
2669         if (!m_context_is_es)
2670         {
2671                 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2672                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2673
2674                 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2675                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2676         }
2677 }
2678
2679 /** Verifies that texutre is filled with 0
2680  *
2681  * @param texture_id Id of texture
2682  *
2683  * @return true when image is filled with 0, false otherwise
2684  **/
2685 bool ImageLoadStoreTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
2686 {
2687         static const GLuint height   = 16;
2688         static const GLuint width       = 16;
2689         static const GLuint n_pixels = height * width;
2690
2691         // OpenGL ES has undefined out-of-bound behavior - no verification
2692         if (m_context_is_es)
2693                 return true;
2694
2695         gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2696         GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2697
2698         bool result = true;
2699
2700         if (R8 == m_test_case)
2701         {
2702                 static const GLuint n_channels = 1;
2703
2704                 std::vector<GLubyte> pixels(n_pixels * n_channels);
2705                 initPixels(pixels, n_pixels, n_channels);
2706
2707                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2708
2709                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2710
2711                 /* Unbind */
2712                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2713
2714                 /* Verify */
2715                 for (GLuint i = 0; i < n_pixels; ++i)
2716                 {
2717                         const GLubyte expected_red = 0;
2718                         const GLubyte drawn_red = pixels[i];
2719
2720                         if (expected_red != drawn_red)
2721                         {
2722                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2723                                                                    << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2724                                                                    << tcu::TestLog::EndMessage;
2725
2726                                 result = false;
2727                                 break;
2728                         }
2729                 }
2730         }
2731         else if (RG8_SNORM == m_test_case)
2732         {
2733                 static const GLuint n_channels = 2;
2734
2735                 std::vector<GLbyte> pixels(n_pixels * n_channels);
2736                 initPixels(pixels, n_pixels, n_channels);
2737
2738                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2739
2740                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2741
2742                 /* Unbind */
2743                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2744
2745                 /* Verify */
2746                 for (GLuint i = 0; i < n_pixels; ++i)
2747                 {
2748                         const GLbyte expected_red   = 0;
2749                         const GLbyte expected_green = 0;
2750                         const GLbyte drawn_red          = pixels[i * n_channels + 0];
2751                         const GLbyte drawn_green        = pixels[i * n_channels + 1];
2752
2753                         if ((expected_red != drawn_red) || (expected_green != drawn_green))
2754                         {
2755                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2756                                                                    << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2757                                                                    << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2758
2759                                 result = false;
2760                                 break;
2761                         }
2762                 }
2763         }
2764         else if (RGBA32F == m_test_case)
2765         {
2766                 static const GLuint n_channels = 4;
2767
2768                 std::vector<GLfloat> pixels(n_pixels * n_channels);
2769                 for (GLuint i = 0; i < n_pixels; ++i)
2770                 {
2771                         GLuint  idx             = i * n_channels;
2772                         GLfloat value   = static_cast<GLfloat>(i) / n_pixels;
2773                         pixels[idx + 0] = value;
2774                         pixels[idx + 1] = value;
2775                         pixels[idx + 2] = value;
2776                         pixels[idx + 3] = value;
2777                 }
2778
2779                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2780
2781                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
2782
2783                 /* Unbind */
2784                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2785
2786                 /* Verify */
2787                 for (GLuint i = 0; i < n_pixels; ++i)
2788                 {
2789                         const GLfloat expected_red   = 0.0f;
2790                         const GLfloat expected_green = 0.0f;
2791                         const GLfloat expected_blue  = 0.0f;
2792                         const GLfloat expected_alpha = 0.0f;
2793                         const GLuint  idx                        = i * n_channels;
2794                         const GLfloat drawn_red          = pixels[idx + 0];
2795                         const GLfloat drawn_green       = pixels[idx + 1];
2796                         const GLfloat drawn_blue         = pixels[idx + 2];
2797                         const GLfloat drawn_alpha       = pixels[idx + 3];
2798
2799                         if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2800                                 (expected_alpha != drawn_alpha))
2801                         {
2802                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2803                                                                    << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2804                                                                    << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2805                                                                    << ". At offset: " << i << tcu::TestLog::EndMessage;
2806
2807                                 result = false;
2808                                 break;
2809                         }
2810                 }
2811         }
2812         else if (R32UI_MIPMAP == m_test_case)
2813         {
2814                 static const GLuint n_channels = 1;
2815
2816                 std::vector<GLuint> pixels(n_pixels * n_channels);
2817                 initPixels(pixels, n_pixels, n_channels);
2818
2819                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2820
2821                 Texture::GetData(gl, 1 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2822
2823                 /* Unbind */
2824                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2825
2826                 /* Verify */
2827                 for (GLuint i = 0; i < n_pixels; ++i)
2828                 {
2829                         const GLuint expected_red = 0;
2830                         const GLuint drawn_red  = pixels[i];
2831
2832                         if (expected_red != drawn_red)
2833                         {
2834                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2835                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2836                                                                    << tcu::TestLog::EndMessage;
2837
2838                                 result = false;
2839                                 break;
2840                         }
2841                 }
2842         }
2843         else if (R32UI_MULTISAMPLE == m_test_case)
2844         {
2845                 static const GLuint n_channels = 1;
2846
2847                 /* Compute shader */
2848                 static const GLchar* cs = "${VERSION}\n"
2849                                                                   "\n"
2850                                                                   "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2851                                                                   "\n"
2852                                                                   "layout (location = 1)        writeonly uniform uimage2D   uni_destination_image;\n"
2853                                                                   "layout (location = 0, r32ui) readonly  uniform uimage2DMS uni_source_image;\n"
2854                                                                   "\n"
2855                                                                   "void main()\n"
2856                                                                   "{\n"
2857                                                                   "    const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2858                                                                   "\n"
2859                                                                   "    const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2860                                                                   "    const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2861                                                                   "    const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2862                                                                   "    const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2863                                                                   "\n"
2864                                                                   "    if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2865                                                                   "    {\n"
2866                                                                   "        imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2867                                                                   "    }\n"
2868                                                                   "    else\n"
2869                                                                   "    {\n"
2870                                                                   "        imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2871                                                                   "    }\n"
2872                                                                   "}\n"
2873                                                                   "\n";
2874
2875                 Program program(gl);
2876                 Texture destination_texture(gl);
2877
2878                 Texture::Generate(gl, destination_texture.m_id);
2879                 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2880                 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2881
2882                 program.Init(cs, "", "", "", "", "");
2883                 program.Use();
2884                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2885                                                         GL_READ_ONLY, GL_R32UI);
2886                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2887                 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2888                                                         0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2889                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2890
2891                 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2892                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2893
2894                 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2895                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2896
2897                 gl.dispatchCompute(16, 16, 1);
2898                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2899
2900                 /* Pixels buffer initialization */
2901                 std::vector<GLuint> pixels(n_pixels * n_channels);
2902                 initPixels(pixels, n_pixels, n_channels);
2903
2904                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2905
2906                 /* Unbind */
2907                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2908
2909                 /* Verify */
2910                 for (GLuint i = 0; i < n_pixels; ++i)
2911                 {
2912                         const GLuint expected_red = 1;
2913                         const GLuint drawn_red  = pixels[i];
2914
2915                         if (expected_red != drawn_red)
2916                         {
2917                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2918                                                                    << ". Expected value: " << expected_red << " at offset: " << i
2919                                                                    << tcu::TestLog::EndMessage;
2920
2921                                 result = false;
2922                                 break;
2923                         }
2924                 }
2925         }
2926
2927         return result;
2928 }
2929
2930 /** Verifies that texutre is filled with increasing values
2931  *
2932  * @param texture_id Id of texture
2933  *
2934  * @return true when image is filled with increasing values, false otherwise
2935  **/
2936 bool ImageLoadStoreTest::verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id)
2937 {
2938         static const GLuint height   = 16;
2939         static const GLuint width       = 16;
2940         static const GLuint n_pixels = height * width;
2941
2942         gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2943         GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2944
2945         bool result = true;
2946
2947         if (R8 == m_test_case)
2948         {
2949                 static const GLuint n_channels = 1;
2950
2951                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2952
2953                 std::vector<GLubyte> pixels(n_pixels * n_channels);
2954                 initPixels(pixels, n_pixels, n_channels);
2955
2956                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2957
2958                 /* Unbind */
2959                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2960
2961                 /* Verify */
2962                 for (GLuint i = 0; i < n_pixels; ++i)
2963                 {
2964                         const GLubyte expected_red = static_cast<GLubyte>(i);
2965                         const GLubyte drawn_red = pixels[i];
2966
2967                         if (expected_red != drawn_red)
2968                         {
2969                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2970                                                                    << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2971                                                                    << tcu::TestLog::EndMessage;
2972
2973                                 result = false;
2974                                 break;
2975                         }
2976                 }
2977         }
2978         else if (RG8_SNORM == m_test_case)
2979         {
2980                 static const GLuint n_channels = 2;
2981
2982                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2983
2984                 std::vector<GLbyte> pixels(n_pixels * n_channels);
2985                 initPixels(pixels, n_pixels, n_channels);
2986
2987                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2988
2989                 /* Unbind */
2990                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2991
2992                 /* Verify */
2993                 for (GLuint i = 0; i < n_pixels; ++i)
2994                 {
2995                         const GLbyte expected_red   = static_cast<GLubyte>((i % 16) - 8);
2996                         const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
2997                         const GLbyte drawn_red          = pixels[i * n_channels + 0];
2998                         const GLbyte drawn_green        = pixels[i * n_channels + 1];
2999
3000                         if ((expected_red != drawn_red) || (expected_green != drawn_green))
3001                         {
3002                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
3003                                                                    << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
3004                                                                    << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
3005
3006                                 result = false;
3007                                 break;
3008                         }
3009                 }
3010         }
3011         else if (RGBA32F == m_test_case)
3012         {
3013                 static const GLuint n_channels = 4;
3014
3015                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3016
3017                 std::vector<GLfloat> pixels(n_pixels * n_channels);
3018                 for (GLuint i = 0; i < n_pixels; ++i)
3019                 {
3020                         GLfloat value                      = static_cast<GLfloat>(i) / n_pixels;
3021                         pixels[i * n_channels + 0] = value;
3022                         pixels[i * n_channels + 1] = value;
3023                         pixels[i * n_channels + 2] = value;
3024                         pixels[i * n_channels + 3] = value;
3025                 }
3026
3027                 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
3028
3029                 /* Unbind */
3030                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3031
3032                 /* Verify */
3033                 for (GLuint i = 0; i < n_pixels; ++i)
3034                 {
3035                         const GLfloat expected_red   = (GLfloat)(i % 16) / 16.0f;
3036                         const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
3037                         const GLfloat expected_blue  = (GLfloat)i / 256.0f;
3038                         const GLfloat expected_alpha = 1.0f;
3039                         const GLuint  idx                        = i * n_channels;
3040                         const GLfloat drawn_red          = pixels[idx + 0];
3041                         const GLfloat drawn_green       = pixels[idx + 1];
3042                         const GLfloat drawn_blue         = pixels[idx + 2];
3043                         const GLfloat drawn_alpha       = pixels[idx + 3];
3044
3045                         if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
3046                                 (expected_alpha != drawn_alpha))
3047                         {
3048                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
3049                                                                    << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
3050                                                                    << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
3051                                                                    << ". At offset: " << i << tcu::TestLog::EndMessage;
3052
3053                                 result = false;
3054                                 break;
3055                         }
3056                 }
3057         }
3058         else if (R32UI_MIPMAP == m_test_case)
3059         {
3060                 static const GLuint n_channels = 4;
3061
3062                 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3063
3064                 std::vector<GLuint> pixels(n_pixels * n_channels);
3065                 initPixels(pixels, n_pixels, n_channels);
3066
3067                 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3068
3069                 /* Unbind */
3070                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3071
3072                 /* Verify */
3073                 for (GLuint i = 0; i < n_pixels; ++i)
3074                 {
3075                         const GLuint expected_red = i;
3076                         const GLuint drawn_red  = pixels[i * n_channels];
3077
3078                         if (expected_red != drawn_red)
3079                         {
3080                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3081                                                                    << ". Expected value: " << expected_red << " at offset: " << i
3082                                                                    << tcu::TestLog::EndMessage;
3083
3084                                 result = false;
3085                                 break;
3086                         }
3087                 }
3088         }
3089         else if (R32UI_MULTISAMPLE == m_test_case)
3090         {
3091                 static const GLuint n_channels = 1;
3092
3093                 /* Compute shader */
3094                 static const GLchar* cs =
3095                         "${VERSION}\n"
3096                         "\n"
3097                         "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3098                         "\n"
3099                         "layout (location = 1)        writeonly uniform uimage2D   uni_destination_image;\n"
3100                         "layout (location = 0, r32ui) readonly  uniform uimage2DMS uni_source_image;\n"
3101                         "\n"
3102                         "void main()\n"
3103                         "{\n"
3104                         "    const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
3105                         "    const uint  index = gl_WorkGroupID.y * 16 + gl_WorkGroupID.x;\n"
3106                         "\n"
3107                         "    const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
3108                         "    const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
3109                         "    const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
3110                         "    const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
3111                         "\n"
3112                         "    if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3))))\n"
3113                         "    {\n"
3114                         "        imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
3115                         "    }\n"
3116                         "    else\n"
3117                         "    {\n"
3118                         "        imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
3119                         "    }\n"
3120                         "}\n"
3121                         "\n";
3122
3123                 Program program(gl);
3124                 Texture destination_texture(gl);
3125
3126                 Texture::Generate(gl, destination_texture.m_id);
3127                 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
3128                 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
3129
3130                 program.Init(cs, "", "", "", "", "");
3131                 program.Use();
3132                 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
3133                                                         GL_READ_ONLY, GL_R32UI);
3134                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3135                 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
3136                                                         0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
3137                 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3138
3139                 gl.uniform1i(0 /* location */, 0 /* image unit*/);
3140                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3141
3142                 gl.uniform1i(1 /* location */, 1 /* image unit*/);
3143                 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3144
3145                 gl.dispatchCompute(16, 16, 1);
3146                 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3147
3148                 /* Pixels buffer initialization */
3149                 std::vector<GLuint> pixels(n_pixels * n_channels);
3150                 initPixels(pixels, n_pixels, n_channels);
3151
3152                 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3153
3154                 /* Unbind */
3155                 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3156
3157                 /* Verify */
3158                 for (GLuint i = 0; i < n_pixels; ++i)
3159                 {
3160                         const GLuint expected_red = 1;
3161                         const GLuint drawn_red  = pixels[i];
3162
3163                         if (expected_red != drawn_red)
3164                         {
3165                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3166                                                                    << ". Expected value: " << expected_red << " at offset: " << i
3167                                                                    << tcu::TestLog::EndMessage;
3168
3169                                 result = false;
3170                                 break;
3171                         }
3172                 }
3173         }
3174
3175         return result;
3176 }
3177
3178 /* StorageBufferTest constants */
3179 const GLfloat StorageBufferTest::m_destination_data[4]  = { 1.0f, 1.0f, 1.0f, 1.0f };
3180 const GLfloat StorageBufferTest::m_source_data[4]               = { 2.0f, 3.0f, 4.0f, 5.0f };
3181
3182 /** Constructor
3183  *
3184  * @param testCtx Test context
3185  * @param apiType Api type
3186  **/
3187 StorageBufferTest::StorageBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3188         : RobustnessBase(testCtx, "storage_buffer", "Verifies that out-of-bound access to SSBO is discared or resutls in 0",
3189                                          apiType)
3190         , m_test_case(VALID)
3191 {
3192         /* Nothing to be done here */
3193 }
3194
3195
3196 /** Execute test
3197  *
3198  * @return tcu::TestNode::STOP
3199  **/
3200 tcu::TestNode::IterateResult StorageBufferTest::iterate()
3201 {
3202         de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3203         if (!robustContext.get())
3204                 return STOP;
3205
3206         /* GL entry points */
3207         const Functions& gl = robustContext->getFunctions();
3208
3209         /* Test result indicator */
3210         bool test_result = true;
3211
3212         GLuint test_offsets[] = {
3213                 16,                              // close fetch
3214                 4 * 1024,                // near fetch (4K of the end of the object)
3215                 1024 * 1024,     // medium fetch (1MB past the end of the object)
3216                 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3217         };
3218
3219         /* Iterate over all cases */
3220         while (LAST != m_test_case)
3221         {
3222                 /* Test case objects */
3223                 Buffer  destination_buffer(gl);
3224                 Buffer  source_buffer(gl);
3225                 Program program(gl);
3226
3227                 /* Buffers initialization */
3228                 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_destination_data),
3229                                                                         m_destination_data);
3230                 source_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_source_data), m_source_data);
3231
3232                 destination_buffer.BindBase(0);
3233                 source_buffer.BindBase(1);
3234
3235                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3236                 {
3237                         /* Initialize shader */
3238                         const std::string& cs = getComputeShader(test_offsets[i]);
3239                         program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3240                         program.Use();
3241
3242                         /* Dispatch compute */
3243                         gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3244                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3245
3246                         /* Set memory barrier */
3247                         gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3248                         GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3249
3250                         /* Verify results */
3251                         destination_buffer.Bind();
3252                         GLfloat* buffer_data =
3253                                 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(m_destination_data), GL_MAP_READ_BIT);
3254                         GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3255
3256                         test_result &= verifyResults(buffer_data);
3257
3258                         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3259                         GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3260                 }
3261
3262                 /* Increment */
3263                 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3264         }
3265
3266         /* Set result */
3267         if (true == test_result)
3268         {
3269                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3270         }
3271         else
3272         {
3273                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3274         }
3275
3276         /* Done */
3277         return tcu::TestNode::STOP;
3278 }
3279
3280 /** Prepare shader for current test case
3281  *
3282  * @return Source
3283  **/
3284 std::string StorageBufferTest::getComputeShader(GLuint offset)
3285 {
3286         static const GLchar* source = "${VERSION}\n"
3287                                                                   "\n"
3288                                                                   "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3289                                                                   "\n"
3290                                                                   "layout (binding = 1, std430) buffer Source {\n"
3291                                                                   "    float data[];\n"
3292                                                                   "} source;\n"
3293                                                                   "\n"
3294                                                                   "layout (binding = 0, std430) buffer Destination {\n"
3295                                                                   "    float data[];\n"
3296                                                                   "} destination;\n"
3297                                                                   "\n"
3298                                                                   "void main()\n"
3299                                                                   "{\n"
3300                                                                   "    uint index_destination = gl_LocalInvocationID.x + ${DST_OFFSET}U;\n"
3301                                                                   "    uint index_source      = gl_LocalInvocationID.x + ${SRC_OFFSET}U;\n"
3302                                                                   "\n"
3303                                                                   "    destination.data[index_destination] = source.data[index_source];\n"
3304                                                                   "}\n"
3305                                                                   "\n";
3306
3307         std::stringstream offset_stream;
3308         offset_stream << offset;
3309
3310         m_specializationMap["DST_OFFSET"] = "0";
3311         m_specializationMap["SRC_OFFSET"] = "0";
3312         if (m_test_case == SOURCE_INVALID)
3313                 m_specializationMap["SRC_OFFSET"] = offset_stream.str();
3314         else if (m_test_case == DESTINATION_INVALID)
3315                 m_specializationMap["DST_OFFSET"] = offset_stream.str();
3316
3317         return tcu::StringTemplate(source).specialize(m_specializationMap);
3318 }
3319
3320 /** Verify test case results
3321  *
3322  * @param buffer_data Buffer data to verify
3323  *
3324  * @return true if buffer_data is as expected, false othrewise
3325  **/
3326 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
3327 {
3328         /* KHR_robust_buffer_access_behavior (and also GL 4.5 and later) states
3329          * which values can be expected when reading or writing outside of a
3330          * buffer's range. If supported, we will compare results against those
3331          * expectations.
3332          *
3333          * Otherwise, we will attempt to match results against previously observed
3334          * and valid behavior.
3335          */
3336         static const GLfloat expected_data_valid[4]                                = { 2.0f, 3.0f, 4.0f, 5.0f };
3337         static const GLfloat expected_data_invalid_source[4]       = { 0.0f, 0.0f, 0.0f, 0.0f };
3338         static const GLfloat expected_data_invalid_destination[4]  = { 1.0f, 1.0f, 1.0f, 1.0f };
3339
3340         /* OpenGL ES has undefined out-of-bound behavior - verify only valid result*/
3341         if (m_context_is_es && (m_test_case != VALID))
3342                 return true;
3343
3344         /* Prepare expected data const for proper case*/
3345         const GLchar*  name                                = 0;
3346         bool               check_expected_data = false;
3347         const GLfloat* expected_data       = 0;
3348         switch (m_test_case)
3349         {
3350         case VALID:
3351                 name                            = "valid indices";
3352                 check_expected_data     = true;
3353                 expected_data           = expected_data_valid;
3354                 break;
3355         case SOURCE_INVALID:
3356                 name                            = "invalid source indices";
3357                 if (m_has_khr_robust_buffer_access)
3358                 {
3359                         for (int b = 0; b < 4; b++)
3360                         {
3361                                 /* Each out-of-range read can either be 0 or any value within
3362                                  * the source buffer.
3363                                  * */
3364                                 bool valid = false;
3365                                 if (buffer_data[b] == 0.0f)
3366                                 {
3367                                         valid = true;
3368                                 }
3369                                 else
3370                                 {
3371                                         for (int c = 0; c < 4 && !valid; c++)
3372                                         {
3373                                                 if (buffer_data[b] == m_source_data[c])
3374                                                 {
3375                                                         valid = true;
3376                                                 }
3377                                         }
3378                                 }
3379                                 if (!valid)
3380                                 {
3381                                         m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3382                                                                            << tcu::TestLog::EndMessage;
3383                                 }
3384                         }
3385                 }
3386                 else
3387                 {
3388                         check_expected_data     = true;
3389                         expected_data           = expected_data_invalid_source;
3390                 }
3391                 break;
3392         case DESTINATION_INVALID:
3393                 name                            = "invalid destination indices";
3394                 if (m_has_khr_robust_buffer_access)
3395                 {
3396                         for (int b = 0; b < 4; b++)
3397                         {
3398                                 bool valid = false;
3399                                 /* Each out-of-range write can either be discarded (in which
3400                                  * case it would have the original destination value) or it
3401                                  * could write any value within the buffer (so we need to check
3402                                  * against each possible source value).
3403                                  */
3404                                 if (buffer_data[b] == m_destination_data[b])
3405                                 {
3406                                         valid = true;
3407                                 }
3408                                 else
3409                                 {
3410                                         for (int c = 0; c < 4 && !valid; c++)
3411                                         {
3412                                                 if (buffer_data[b] == m_source_data[c])
3413                                                 {
3414                                                         valid = true;
3415                                                 }
3416                                         }
3417                                 }
3418                                 if (!valid)
3419                                 {
3420                                         m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3421                                                                            << tcu::TestLog::EndMessage;
3422                                 }
3423                         }
3424                 }
3425                 else
3426                 {
3427                         check_expected_data     = true;
3428                         expected_data           = expected_data_invalid_destination;
3429                 }
3430                 break;
3431         default:
3432                 TCU_FAIL("Invalid enum");
3433         }
3434
3435         if (check_expected_data)
3436         {
3437                 /* Verify buffer data */
3438                 int size = static_cast<int>(sizeof(GLfloat) * 4);
3439                 if (0 != memcmp(expected_data, buffer_data, size))
3440                 {
3441                         m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3442                                                            << tcu::TestLog::EndMessage;
3443                         return false;
3444                 }
3445         }
3446
3447         return true;
3448 }
3449
3450 /** Constructor
3451  *
3452  * @param context Test context
3453  **/
3454 UniformBufferTest::UniformBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3455         : RobustnessBase(testCtx, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls in 0", apiType)
3456         , m_test_case(VALID)
3457 {
3458         /* Nothing to be done here */
3459 }
3460
3461 /** Execute test
3462  *
3463  * @return tcu::TestNode::STOP
3464  **/
3465 tcu::TestNode::IterateResult UniformBufferTest::iterate()
3466 {
3467         de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3468         if (!robustContext.get())
3469                 return STOP;
3470
3471         static const GLfloat destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3472         /* The source buffer is packed std140 so we need vec4s */
3473         static const GLfloat source_data[16] = {
3474                 2.0f, 0.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f,
3475         };
3476
3477         GLuint test_offsets[] = {
3478                 16,                              // close fetch
3479                 4 * 1024,                // near fetch (4K of the end of the object)
3480                 1024 * 1024,     // medium fetch (1MB past the end of the object)
3481                 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3482         };
3483
3484         /* GL entry points */
3485         const Functions& gl = robustContext->getFunctions();
3486
3487         /* Test result indicator */
3488         bool test_result = true;
3489
3490         /* Iterate over all cases */
3491         while (LAST != m_test_case)
3492         {
3493                 /* Test case objects */
3494                 Buffer  destination_buffer(gl);
3495                 Buffer  source_buffer(gl);
3496                 Program program(gl);
3497
3498                 /* Buffers initialization */
3499                 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(destination_data),
3500                                                                         destination_data);
3501                 source_buffer.InitData(GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, sizeof(source_data), source_data);
3502
3503                 destination_buffer.BindBase(0);
3504                 source_buffer.BindBase(0);
3505
3506                 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3507                 {
3508                         /* Initialize shader */
3509                         const std::string& cs = getComputeShader(test_offsets[i]);
3510                         program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3511                         program.Use();
3512
3513                         /* Dispatch compute */
3514                         gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3515                         GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3516
3517                         /* Set memory barrier */
3518                         gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3519                         GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3520
3521                         /* Verify results */
3522                         destination_buffer.Bind();
3523                         GLfloat* buffer_data =
3524                                 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(destination_data), GL_MAP_READ_BIT);
3525                         GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3526
3527                         test_result &= verifyResults(buffer_data);
3528
3529                         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3530                         GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3531                 }
3532
3533                 /* Increment */
3534                 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3535         }
3536
3537         /* Set result */
3538         if (true == test_result)
3539         {
3540                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3541         }
3542         else
3543         {
3544                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3545         }
3546
3547         /* Done */
3548         return tcu::TestNode::STOP;
3549 }
3550
3551 /** Prepare shader for current test case
3552  *
3553  * @return Source
3554  **/
3555 std::string UniformBufferTest::getComputeShader(GLuint offset)
3556 {
3557         static const GLchar* source = "${VERSION}\n"
3558                                                                   "\n"
3559                                                                   "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3560                                                                   "\n"
3561                                                                   "layout (binding = 0, std140) uniform Source {\n"
3562                                                                   "    float data[16];\n"
3563                                                                   "} source;\n"
3564                                                                   "\n"
3565                                                                   "layout (binding = 0, std430) buffer Destination {\n"
3566                                                                   "    float data[];\n"
3567                                                                   "} destination;\n"
3568                                                                   "\n"
3569                                                                   "void main()\n"
3570                                                                   "{\n"
3571                                                                   "    uint index_destination = gl_LocalInvocationID.x;\n"
3572                                                                   "    uint index_source      = gl_LocalInvocationID.x + ${OFFSET}U;\n"
3573                                                                   "\n"
3574                                                                   "    destination.data[index_destination] = source.data[index_source];\n"
3575                                                                   "}\n"
3576                                                                   "\n";
3577
3578         m_specializationMap["OFFSET"] = "0";
3579         if (m_test_case == SOURCE_INVALID)
3580         {
3581                 std::stringstream offset_stream;
3582                 offset_stream << offset;
3583                 m_specializationMap["OFFSET"] = offset_stream.str();
3584         }
3585
3586         return tcu::StringTemplate(source).specialize(m_specializationMap);
3587 }
3588
3589 /** Verify test case results
3590  *
3591  * @param buffer_data Buffer data to verify
3592  *
3593  * @return true if buffer_data is as expected, false othrewise
3594  **/
3595 bool UniformBufferTest::verifyResults(GLfloat* buffer_data)
3596 {
3597         static const GLfloat expected_data_valid[4]                      = { 2.0f, 3.0f, 4.0f, 5.0f };
3598         static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3599
3600         int size = static_cast<int>(sizeof(GLfloat) * 4);
3601
3602         /* Prepare expected data const for proper case*/
3603         const GLfloat* expected_data = 0;
3604         const GLchar*  name                      = 0;
3605         switch (m_test_case)
3606         {
3607         case VALID:
3608                 expected_data = expected_data_valid;
3609                 name              = "valid indices";
3610                 break;
3611         case SOURCE_INVALID:
3612                 expected_data = expected_data_invalid_source;
3613                 name              = "invalid source indices";
3614                 break;
3615         default:
3616                 TCU_FAIL("Invalid enum");
3617         }
3618
3619         /* Verify buffer data */
3620         if (0 != memcmp(expected_data, buffer_data, size))
3621         {
3622                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" << tcu::TestLog::EndMessage;
3623                 return false;
3624         }
3625
3626         return true;
3627 }
3628 } /* RobustBufferAccessBehavior */
3629
3630 /** Constructor.
3631  *
3632  *  @param context Rendering context.
3633  **/
3634 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(tcu::TestContext& testCtx, glu::ApiType apiType)
3635         : tcu::TestCaseGroup(testCtx, "robust_buffer_access_behavior",
3636                                                  "Verifies \"robust buffer access behavior\" functionality")
3637         , m_ApiType(apiType)
3638 {
3639         /* Left blank on purpose */
3640 }
3641
3642 /** Initializes a multi_bind test group.
3643  *
3644  **/
3645 void RobustBufferAccessBehaviorTests::init(void)
3646 {
3647         addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_testCtx, m_ApiType));
3648         addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_testCtx, m_ApiType));
3649         addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_testCtx, m_ApiType));
3650         addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_testCtx, m_ApiType));
3651         addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_testCtx, m_ApiType));
3652 }
3653
3654 } /* glcts */