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