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