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