• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  **/
Buffer(const glw::Functions & gl)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  **/
~Buffer()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  **/
InitData(glw::GLenum target,glw::GLenum usage,glw::GLsizeiptr size,const glw::GLvoid * data)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  **/
Release()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  **/
Bind() const114 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  **/
BindBase(glw::GLuint index) const123 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  **/
Bind(const glw::Functions & gl,glw::GLuint id,glw::GLenum target)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  **/
BindBase(const glw::Functions & gl,glw::GLuint id,glw::GLenum target,glw::GLuint index)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  **/
Data(const glw::Functions & gl,glw::GLenum target,glw::GLenum usage,glw::GLsizeiptr size,const glw::GLvoid * data)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  **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)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  **/
SubData(const glw::Functions & gl,glw::GLenum target,glw::GLintptr offset,glw::GLsizeiptr size,glw::GLvoid * data)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  **/
Framebuffer(const glw::Functions & gl)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  **/
~Framebuffer()218 Framebuffer::~Framebuffer()
219 {
220 	Release();
221 }
222 
223 /** Release texture instance
224  *
225  **/
Release()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  **/
AttachTexture(const glw::Functions & gl,glw::GLenum target,glw::GLenum attachment,glw::GLuint texture_id,glw::GLint level,glw::GLuint width,glw::GLuint height)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  **/
Bind(const glw::Functions & gl,glw::GLenum target,glw::GLuint id)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  **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)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  **/
Program(const glw::Functions & gl)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  **/
~Program()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  **/
Init(const std::string & compute_shader,const std::string & fragment_shader,const std::string & geometry_shader,const std::string & tesselation_control_shader,const std::string & tesselation_evaluation_shader,const std::string & vertex_shader)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  **/
Release()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  **/
Use() const374 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  **/
Attach(const glw::Functions & gl,glw::GLuint program_id,glw::GLuint shader_id)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  **/
Create(const glw::Functions & gl,glw::GLuint & out_id)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  **/
Link(const glw::Functions & gl,glw::GLuint id)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  **/
Use(const glw::Functions & gl,glw::GLuint id)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  **/
Shader(const glw::Functions & gl)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  **/
~Shader()477 Shader::~Shader()
478 {
479 	Release();
480 }
481 
482 /** Initialize shader instance
483  *
484  * @param stage  Shader stage
485  * @param source Source code
486  **/
Init(glw::GLenum stage,const std::string & source)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  **/
Release()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  **/
Compile(const glw::Functions & gl,glw::GLuint id)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  **/
Create(const glw::Functions & gl,glw::GLenum stage,glw::GLuint & out_id)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  **/
Source(const glw::Functions & gl,glw::GLuint id,const std::string & source)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  **/
Texture(const glw::Functions & gl)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  **/
~Texture()602 Texture::~Texture()
603 {
604 	Release();
605 }
606 
607 /** Release texture instance
608  *
609  **/
Release()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  **/
Bind(const glw::Functions & gl,glw::GLuint id,glw::GLenum target)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  **/
CompressedImage(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth,glw::GLsizei image_size,const glw::GLvoid * data)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  **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)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  **/
GetData(const glw::Functions & gl,glw::GLint level,glw::GLenum target,glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)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  **/
GetData(const glw::Functions & gl,glw::GLuint id,glw::GLint level,glw::GLuint width,glw::GLuint height,glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)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  **/
GetLevelParameter(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum pname,glw::GLint * param)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  **/
Image(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth,glw::GLenum format,glw::GLenum type,const glw::GLvoid * data)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  **/
Storage(const glw::Functions & gl,glw::GLenum target,glw::GLsizei levels,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth)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  **/
SubImage(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLint x,glw::GLint y,glw::GLint z,glw::GLsizei width,glw::GLsizei height,glw::GLsizei depth,glw::GLenum format,glw::GLenum type,const glw::GLvoid * pixels)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  **/
VertexArray(const glw::Functions & gl)917 VertexArray::VertexArray(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
918 {
919 }
920 
921 /** Destructor
922  *
923  **/
~VertexArray()924 VertexArray::~VertexArray()
925 {
926 	Release();
927 }
928 
929 /** Release vertex array object instance
930  *
931  **/
Release()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  **/
Bind(const glw::Functions & gl,glw::GLuint id)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  **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)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>
initPixels(std::vector<TYPE> & pixels,GLuint n_pixels,GLuint n_channels)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 
RobustnessBase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ApiType apiType)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 
createRobustContext(glu::ResetNotificationStrategy reset)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  **/
VertexBufferObjectsTest(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
iterate()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  **/
getFragmentShader()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  **/
getVertexShader()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  **/
cleanTexture(const Functions & gl,glw::GLuint texture_id)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  **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)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  **/
verifyValidResults(const Functions & gl,glw::GLuint texture_id)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  **/
verifyResults(const Functions & gl,glw::GLuint texture_id)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  **/
TexelFetchTest(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
TexelFetchTest(tcu::TestContext & testCtx,const char * name,const char * description,glu::ApiType apiType)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  **/
iterate()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  **/
getFragmentShader(const glu::ContextType &,bool is_case_valid,GLuint fetch_offset)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  **/
getGeometryShader()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  **/
getVertexShader()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  **/
getTestCaseName() const1649 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  **/
prepareTexture(const Functions & gl,bool is_source,glw::GLuint texture_id)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 (${QUALIFIER​S}) 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["QUALIFIER​S"] = "binding = 0, r32ui";
1826 		}
1827 		else
1828 		{
1829 			m_specializationMap["LOCAL_SIZE"]	= "1";
1830 			m_specializationMap["QUALIFIER​S"] = "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  **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)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  **/
verifyValidResults(const Functions & gl,glw::GLuint texture_id)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  **/
ImageLoadStoreTest(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
iterate()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  **/
getComputeShader(VERSION version,GLuint coord_offset,GLuint sample_offset)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  **/
setTextures(const Functions & gl,glw::GLuint id_destination,glw::GLuint id_source)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  **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)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  **/
verifyValidResults(const glw::Functions & gl,glw::GLuint texture_id)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  **/
StorageBufferTest(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
iterate()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  **/
getComputeShader(GLuint offset)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  **/
verifyResults(GLfloat * buffer_data)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  **/
UniformBufferTest(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
iterate()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  **/
getComputeShader(GLuint offset)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  **/
verifyResults(GLfloat * buffer_data)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  **/
RobustBufferAccessBehaviorTests(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
init(void)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