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