1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * \file glcRobustBufferAccessBehaviorTests.cpp
21 * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
22 */ /*-------------------------------------------------------------------*/
24 #include "glcRobustBufferAccessBehaviorTests.hpp"
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"
43 namespace RobustBufferAccessBehavior
45 /* Buffer constants */
46 const GLuint Buffer::m_invalid_id = -1;
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 */
66 * @param context CTS context.
68 Buffer::Buffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl), m_target(GL_ARRAY_BUFFER)
80 /** Initialize buffer instance
82 * @param target Buffer target
83 * @param usage Buffer usage enum
84 * @param size <size> parameter
85 * @param data <data> parameter
87 void Buffer::InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data)
89 /* Delete previous buffer instance */
95 Bind(m_gl, m_id, m_target);
96 Data(m_gl, m_target, usage, size, data);
99 /** Release buffer instance
102 void Buffer::Release()
104 if (m_invalid_id != m_id)
106 m_gl.deleteBuffers(1, &m_id);
111 /** Binds buffer to its target
114 void Buffer::Bind() const
116 Bind(m_gl, m_id, m_target);
119 /** Binds indexed buffer
121 * @param index <index> parameter
123 void Buffer::BindBase(glw::GLuint index) const
125 BindBase(m_gl, m_id, m_target, index);
128 /** Bind buffer to given target
130 * @param gl GL functions
131 * @param id Id of buffer
132 * @param target Buffer target
134 void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
136 gl.bindBuffer(target, id);
137 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
140 /** Binds indexed buffer
142 * @param gl GL functions
143 * @param id Id of buffer
144 * @param target Buffer target
145 * @param index <index> parameter
147 void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index)
149 gl.bindBufferBase(target, index, id);
150 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
153 /** Allocate memory for buffer and sends initial content
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
161 void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
162 const glw::GLvoid* data)
164 gl.bufferData(target, size, data, usage);
165 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
170 * @param gl GL functions
171 * @param out_id Id of buffer
173 void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
175 GLuint id = m_invalid_id;
177 gl.genBuffers(1, &id);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
180 if (m_invalid_id == id)
182 TCU_FAIL("Got invalid id");
188 /** Update range of buffer
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
196 void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
199 gl.bufferSubData(target, offset, size, data);
200 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData");
203 /* Framebuffer constants */
204 const GLuint Framebuffer::m_invalid_id = -1;
208 * @param context CTS context.
210 Framebuffer::Framebuffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
212 /* Nothing to done here */
218 Framebuffer::~Framebuffer()
223 /** Release texture instance
226 void Framebuffer::Release()
228 if (m_invalid_id != m_id)
230 m_gl.deleteFramebuffers(1, &m_id);
235 /** Attach texture to specified attachment
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
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)
248 gl.framebufferTexture(target, attachment, texture_id, level);
249 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
251 gl.viewport(0 /* x */, 0 /* y */, width, height);
252 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
255 /** Binds framebuffer to DRAW_FRAMEBUFFER
257 * @param gl GL functions
258 * @param target Framebuffer target
259 * @param id ID of framebuffer
261 void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id)
263 gl.bindFramebuffer(target, id);
264 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
267 /** Generate framebuffer
270 void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
272 GLuint id = m_invalid_id;
274 gl.genFramebuffers(1, &id);
275 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
277 if (m_invalid_id == id)
279 TCU_FAIL("Invalid id");
285 /* Program constants */
286 const GLuint Program::m_invalid_id = 0;
290 * @param context CTS context.
292 Program::Program(const glw::Functions& gl)
302 /* Nothing to be done here */
313 /** Initialize program instance
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
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)
326 /* Delete previous program */
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);
337 /* Create program, set up transform feedback and attach shaders */
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);
350 /** Release program instance
353 void Program::Release()
355 if (m_invalid_id != m_id)
357 Use(m_gl, m_invalid_id);
359 m_gl.deleteProgram(m_id);
364 m_fragment.Release();
365 m_geometry.Release();
366 m_tess_ctrl.Release();
367 m_tess_eval.Release();
371 /** Set program as active
374 void Program::Use() const
379 /** Attach shader to program
381 * @param gl GL functions
382 * @param program_id Id of program
383 * @param shader_id Id of shader
385 void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id)
388 if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id))
393 gl.attachShader(program_id, shader_id);
394 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
397 /** Create program instance
399 * @param gl GL functions
400 * @param out_id Id of program
402 void Program::Create(const glw::Functions& gl, glw::GLuint& out_id)
404 const GLuint id = gl.createProgram();
405 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
407 if (m_invalid_id == id)
409 TCU_FAIL("Failed to create program");
417 * @param gl GL functions
418 * @param id Id of program
420 void Program::Link(const glw::Functions& gl, glw::GLuint id)
422 GLint status = GL_FALSE;
425 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
427 /* Get link status */
428 gl.getProgramiv(id, GL_LINK_STATUS, &status);
429 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
432 if (GL_TRUE != status)
434 glw::GLint length = 0;
437 /* Get error log length */
438 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
439 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
441 message.resize(length, 0);
444 gl.getProgramInfoLog(id, length, 0, &message[0]);
445 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
447 TCU_FAIL(message.c_str());
453 * @param gl GL functions
454 * @param id Id of program
456 void Program::Use(const glw::Functions& gl, glw::GLuint id)
459 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
462 /* Shader's constants */
463 const GLuint Shader::m_invalid_id = 0;
467 * @param context CTS context.
469 Shader::Shader(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
471 /* Nothing to be done here */
482 /** Initialize shader instance
484 * @param stage Shader stage
485 * @param source Source code
487 void Shader::Init(glw::GLenum stage, const std::string& source)
489 if (true == source.empty())
491 /* No source == no shader */
495 /* Delete any previous shader */
498 Create(m_gl, stage, m_id);
499 Source(m_gl, m_id, source);
504 /** Release shader instance
507 void Shader::Release()
509 if (m_invalid_id != m_id)
511 m_gl.deleteShader(m_id);
518 * @param gl GL functions
519 * @param id Shader id
521 void Shader::Compile(const glw::Functions& gl, glw::GLuint id)
523 GLint status = GL_FALSE;
526 gl.compileShader(id);
527 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
529 /* Get compilation status */
530 gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
531 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
533 /* Log compilation error */
534 if (GL_TRUE != status)
536 glw::GLint length = 0;
539 /* Error log length */
540 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
541 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
543 /* Prepare storage */
544 message.resize(length, 0);
547 gl.getShaderInfoLog(id, length, 0, &message[0]);
548 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
550 TCU_FAIL(message.c_str());
556 * @param gl GL functions
557 * @param stage Shader stage
558 * @param out_id Shader id
560 void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id)
562 const GLuint id = gl.createShader(stage);
563 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
565 if (m_invalid_id == id)
567 TCU_FAIL("Failed to create shader");
573 /** Set shader's source code
575 * @param gl GL functions
576 * @param id Shader id
577 * @param source Shader source code
579 void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source)
581 const GLchar* code = source.c_str();
583 gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
584 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
587 /* Texture static fields */
588 const GLuint Texture::m_invalid_id = -1;
592 * @param context CTS context.
594 Texture::Texture(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
596 /* Nothing to done here */
607 /** Release texture instance
610 void Texture::Release()
612 if (m_invalid_id != m_id)
614 m_gl.deleteTextures(1, &m_id);
619 /** Bind texture to target
621 * @param gl GL functions
622 * @param id Id of texture
623 * @param tex_type Type of texture
625 void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
627 gl.bindTexture(target, id);
628 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
631 /** Set contents of compressed texture
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
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)
650 gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data);
651 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D");
653 case GL_TEXTURE_1D_ARRAY:
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");
659 case GL_TEXTURE_CUBE_MAP:
660 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */,
662 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */,
664 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */,
666 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */,
668 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */,
670 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */,
672 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
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");
680 TCU_FAIL("Invliad enum");
685 /** Generate texture instance
687 * @param gl GL functions
688 * @param out_id Id of texture
690 void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id)
692 GLuint id = m_invalid_id;
694 gl.genTextures(1, &id);
695 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
697 if (m_invalid_id == id)
699 TCU_FAIL("Invalid id");
707 * @param gl GL functions
708 * @param target Texture target
709 * @param format Format of data
710 * @param type Type of data
711 * @param out_data Buffer for data
713 void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
714 glw::GLenum type, glw::GLvoid* out_data)
716 gl.getTexImage(target, level, format, type, out_data);
717 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
722 * @param gl GL functions
723 * @param id Texture id
724 * @param level Mipmap level
725 * @param width Texture width
726 * @param height Texture height
727 * @param format Format of data
728 * @param type Type of data
729 * @param out_data Buffer for data
731 void Texture::GetData(const glw::Functions& gl, glw::GLuint id, glw::GLint level, glw::GLuint width, glw::GLuint height,
732 glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
735 gl.genFramebuffers(1, &fbo);
736 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
737 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
738 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
739 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, level);
740 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
742 gl.readPixels(0, 0, width, height, format, type, out_data);
743 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
745 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
748 /** Generate texture instance
750 * @param gl GL functions
751 * @param target Texture target
752 * @param level Mipmap level
753 * @param pname Parameter to query
754 * @param param Result of query
756 void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
759 gl.getTexLevelParameteriv(target, level, pname, param);
760 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv");
763 /** Set contents of texture
765 * @param gl GL functions
766 * @param target Texture target
767 * @param level Mipmap level
768 * @param internal_format Format of data
769 * @param width Width of texture
770 * @param height Height of texture
771 * @param depth Depth of texture
772 * @param format Format of data
773 * @param type Type of data
774 * @param data Buffer with image data
776 void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
777 glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
778 const glw::GLvoid* data)
783 gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data);
784 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D");
786 case GL_TEXTURE_1D_ARRAY:
788 case GL_TEXTURE_RECTANGLE:
789 gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
790 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
792 case GL_TEXTURE_CUBE_MAP:
793 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format,
795 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format,
797 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format,
799 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format,
801 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format,
803 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format,
805 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
808 case GL_TEXTURE_2D_ARRAY:
809 gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
810 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D");
813 TCU_FAIL("Invliad enum");
818 /** Allocate storage for texture
820 * @param gl GL functions
821 * @param target Texture target
822 * @param levels Number of levels
823 * @param internal_format Internal format of texture
824 * @param width Width of texture
825 * @param height Height of texture
826 * @param depth Depth of texture
828 void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
829 glw::GLuint width, glw::GLuint height, glw::GLuint depth)
834 gl.texStorage1D(target, levels, internal_format, width);
835 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D");
837 case GL_TEXTURE_1D_ARRAY:
839 case GL_TEXTURE_RECTANGLE:
840 case GL_TEXTURE_CUBE_MAP:
841 gl.texStorage2D(target, levels, internal_format, width, height);
842 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
844 case GL_TEXTURE_2D_MULTISAMPLE:
845 gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
846 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
849 case GL_TEXTURE_2D_ARRAY:
850 gl.texStorage3D(target, levels, internal_format, width, height, depth);
851 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
854 TCU_FAIL("Invliad enum");
859 /** Set contents of texture
861 * @param gl GL functions
862 * @param target Texture target
863 * @param level Mipmap level
867 * @param width Width of texture
868 * @param height Height of texture
869 * @param depth Depth of texture
870 * @param format Format of data
871 * @param type Type of data
872 * @param pixels Buffer with image data
874 void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
875 glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
876 glw::GLenum type, const glw::GLvoid* pixels)
881 gl.texSubImage1D(target, level, x, width, format, type, pixels);
882 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D");
884 case GL_TEXTURE_1D_ARRAY:
886 case GL_TEXTURE_RECTANGLE:
887 gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
888 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
890 case GL_TEXTURE_CUBE_MAP:
891 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels);
892 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels);
893 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels);
894 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels);
895 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels);
896 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels);
897 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
900 case GL_TEXTURE_2D_ARRAY:
901 gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
902 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
905 TCU_FAIL("Invliad enum");
910 /* VertexArray constants */
911 const GLuint VertexArray::m_invalid_id = -1;
915 * @param context CTS context.
917 VertexArray::VertexArray(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
924 VertexArray::~VertexArray()
929 /** Release vertex array object instance
932 void VertexArray::Release()
934 if (m_invalid_id != m_id)
938 m_gl.deleteVertexArrays(1, &m_id);
944 /** Binds Vertex array object
946 * @param gl GL functions
947 * @param id ID of vertex array object
949 void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id)
951 gl.bindVertexArray(id);
952 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
955 /** Generates Vertex array object
957 * @param gl GL functions
958 * @param out_id ID of vertex array object
960 void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id)
962 GLuint id = m_invalid_id;
964 gl.genVertexArrays(1, &id);
965 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
967 if (m_invalid_id == id)
969 TCU_FAIL("Invalid id");
975 template <typename TYPE>
976 void initPixels(std::vector<TYPE>& pixels, GLuint n_pixels, GLuint n_channels)
980 for (GLuint i = 0; i < n_pixels; ++i)
981 pixels[i] = static_cast<TYPE>(i);
983 else if (n_channels == 2)
985 for (GLuint i = 0; i < n_pixels; ++i)
988 pixels[idx] = static_cast<TYPE>(i);
989 pixels[idx + 1] = pixels[idx];
992 else if (n_channels == 4)
994 for (GLuint i = 0; i < n_pixels; ++i)
997 pixels[idx] = static_cast<TYPE>(i);
998 pixels[idx + 1] = pixels[idx];
999 pixels[idx + 2] = pixels[idx];
1000 pixels[idx + 3] = pixels[idx];
1004 TCU_FAIL("Unsuported number of channels");
1007 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description,
1008 glu::ApiType apiType)
1009 : tcu::TestCase(testCtx, name, description), m_api_type(apiType), m_has_khr_robust_buffer_access(false)
1013 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
1015 // Create test context to verify if required extensions are available
1017 deqp::Context context(m_testCtx, glu::ContextType(m_api_type));
1018 const glu::ContextInfo& contextInfo = context.getContextInfo();
1019 glu::ContextType context_type = context.getRenderContext().getType();
1020 if (!contextInfo.isExtensionSupported("GL_KHR_robustness") &&
1021 !contextSupports(context_type, glu::ApiType::es(3, 2)))
1023 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_robustness extension not supported");
1027 m_has_khr_robust_buffer_access = contextInfo.isExtensionSupported("GL_KHR_robust_buffer_access_behavior") ||
1028 contextInfo.isExtensionSupported("GL_ARB_robust_buffer_access_behavior") ||
1029 contextSupports(context_type, glu::ApiType::core(4, 5));
1030 if (!m_has_khr_robust_buffer_access && !contextSupports(context_type, glu::ApiType::core(4, 3)))
1032 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
1033 "robust_buffer_access_behavior extension not supported");
1037 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context_type);
1038 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
1039 m_context_is_es = glu::isContextTypeES(context_type);
1042 glu::RenderConfig renderCfg(glu::ContextType(m_api_type, glu::CONTEXT_ROBUST));
1043 const tcu::CommandLine& commandLine = m_testCtx.getCommandLine();
1044 glu::parseRenderConfig(&renderCfg, commandLine);
1046 if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW)
1047 renderCfg.resetNotificationStrategy = reset;
1049 throw tcu::NotSupportedError("Test not supported in non-windowed context");
1051 /* Try to create core/es robusness context */
1052 return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg);
1057 * @param testCtx Test context
1059 VertexBufferObjectsTest::VertexBufferObjectsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1060 : RobustnessBase(testCtx, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero",
1063 /* Nothing to be done */
1068 * @return tcu::TestNode::STOP
1070 tcu::TestNode::IterateResult VertexBufferObjectsTest::iterate()
1072 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1073 if (!robustContext.get())
1076 static const GLuint invalid_elements[] = {
1077 9, 1, 12, 10, 2, 3, 11, 3, 4, 12, 4, 5, 13, 5, 6, 14, 6, 7, 15, 7, 8, 16, 8, 1,
1080 static const GLuint valid_elements[] = {
1081 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
1084 static const GLfloat vertices[] = {
1085 0.0f, 0.0f, 0.0f, /* 0 */
1086 -1.0f, 0.0f, 0.0f, /* 1 */
1087 -1.0f, 1.0f, 0.0f, /* 2 */
1088 0.0f, 1.0f, 0.0f, /* 3 */
1089 1.0f, 1.0f, 0.0f, /* 4 */
1090 1.0f, 0.0f, 0.0f, /* 5 */
1091 1.0f, -1.0f, 0.0f, /* 6 */
1092 0.0f, -1.0f, 0.0f, /* 7 */
1093 -1.0f, -1.0f, 0.0f, /* 8 */
1096 static const GLuint height = 8;
1097 static const GLuint n_vertices = 24;
1098 static const GLuint width = 8;
1100 /* GL entry points */
1101 const Functions& gl = robustContext->getFunctions();
1103 /* Test case objects */
1104 Framebuffer framebuffer(gl);
1105 Program program(gl);
1106 Texture texture(gl);
1107 Buffer elements_buffer(gl);
1108 Buffer vertices_buffer(gl);
1109 VertexArray vao(gl);
1112 VertexArray::Generate(gl, vao.m_id);
1113 VertexArray::Bind(gl, vao.m_id);
1115 /* Buffers initialization */
1116 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(valid_elements), valid_elements);
1117 vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
1119 /* Texture initialization */
1120 Texture::Generate(gl, texture.m_id);
1121 Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
1122 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
1123 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1125 /* Framebuffer initialization*/
1126 Framebuffer::Generate(gl, framebuffer.m_id);
1127 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1128 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width,
1131 /* Shaders initialization */
1132 program.Init("" /* cs */, getFragmentShader(), "" /* gs */, "" /* tcs */, "" /* tes */, getVertexShader());
1133 Program::Use(gl, program.m_id);
1135 /* Vertex buffer initialization */
1136 vertices_buffer.Bind();
1137 gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 12 /* stride */);
1138 gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, NULL);
1139 gl.enableVertexAttribArray(0 /* location */);
1141 /* Binding elements/indices buffer */
1142 elements_buffer.Bind();
1144 cleanTexture(gl, texture.m_id);
1146 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1147 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1149 if (false == verifyValidResults(gl, texture.m_id))
1151 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for valid input" << tcu::TestLog::EndMessage;
1153 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1154 return tcu::TestNode::STOP;
1157 /* Generate invalid data sets */
1158 const GLuint invalid_elements_offsets[] = {
1160 4 * 1024, // near fetch (4K of the end of the object)
1161 1024 * 1024, // medium fetch (1MB past the end of the object)
1162 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
1164 const GLuint invalid_buffers_count = DE_LENGTH_OF_ARRAY(invalid_elements_offsets);
1165 const GLuint item_count = DE_LENGTH_OF_ARRAY(invalid_elements);
1166 GLuint invalid_elements_set[invalid_buffers_count][item_count];
1167 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1169 for (GLuint item_index = 0; item_index < item_count; ++item_index)
1170 invalid_elements_set[buffer_index][item_index] =
1171 invalid_elements[item_index] + invalid_elements_offsets[buffer_index];
1174 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1176 /* Create elements/indices buffer */
1177 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(invalid_elements_set[buffer_index]),
1178 invalid_elements_set[buffer_index]);
1179 elements_buffer.Bind();
1181 cleanTexture(gl, texture.m_id);
1183 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1184 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1186 if (false == verifyInvalidResults(gl, texture.m_id))
1188 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for invalid input"
1189 << tcu::TestLog::EndMessage;
1190 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1191 return tcu::TestNode::STOP;
1196 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1197 return tcu::TestNode::STOP;
1200 /** Prepare shader for current test case
1204 std::string VertexBufferObjectsTest::getFragmentShader()
1206 const char* source = "${VERSION}\n"
1207 "layout (location = 0) out lowp uvec4 out_fs_color;\n"
1210 " out_fs_color = uvec4(1, 255, 255, 255);\n"
1212 return tcu::StringTemplate(source).specialize(m_specializationMap);
1215 /** Prepare shader for current test case
1219 std::string VertexBufferObjectsTest::getVertexShader()
1221 const char* source = "${VERSION}\n"
1222 "layout (location = 0) in vec4 in_vs_position;\n"
1225 " gl_Position = in_vs_position;\n"
1228 return tcu::StringTemplate(source).specialize(m_specializationMap);
1231 /** Fill texture with value 128
1233 * @param texture_id Id of texture
1235 void VertexBufferObjectsTest::cleanTexture(const Functions& gl, glw::GLuint texture_id)
1237 static const GLuint height = 8;
1238 static const GLuint width = 8;
1240 GLubyte pixels[width * height];
1241 for (GLuint i = 0; i < width * height; ++i)
1246 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1248 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
1249 GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
1252 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1255 /** Verifies that texutre is not filled with 1
1257 * @param texture_id Id of texture
1259 * @return false when image is filled with 1, true otherwise
1261 bool VertexBufferObjectsTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1263 // In OpenGL ES there is undefined out-of-bound behavior - no verification
1264 if (m_context_is_es)
1266 return !verifyResults(gl, texture_id);
1269 /** Verifies that texutre is filled with 1
1271 * @param texture_id Id of texture
1273 * @return true when image is filled with 1, false otherwise
1275 bool VertexBufferObjectsTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
1277 return verifyResults(gl, texture_id);
1280 /** Verifies that texutre is filled with 1
1282 * @param texture_id Id of texture
1284 * @return true when image is filled with 1, false otherwise
1286 bool VertexBufferObjectsTest::verifyResults(const Functions& gl, glw::GLuint texture_id)
1288 static const GLuint height = 8;
1289 static const GLuint width = 8;
1290 GLuint pixel_size = 4 * sizeof(GLuint);
1291 GLuint expected_value = 1;
1293 std::vector<GLubyte> pixels(width * height * pixel_size, 0);
1294 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1295 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1296 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1299 for (GLuint i = 0; i < pixels.size(); i += pixel_size)
1301 if (expected_value != pixels[i])
1310 * @param testCtx Test context
1312 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1313 : RobustnessBase(testCtx, "texel_fetch", "Verifies that out-of-bound fetches from texture result in zero", apiType)
1316 /* Nothing to be done */
1321 * @param testCtx Test context
1322 * @param name Test name
1323 * @param description Test description
1324 * @param apiType Api type
1326 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, const char* name, const char* description,
1327 glu::ApiType apiType)
1328 : RobustnessBase(testCtx, name, description, apiType), m_test_case(R8)
1330 /* Nothing to be done */
1335 * @return tcu::TestNode::STOP
1337 tcu::TestNode::IterateResult TexelFetchTest::iterate()
1339 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1340 if (!robustContext.get())
1344 static const GLuint height = 16;
1345 static const GLuint width = 16;
1347 /* GL entry points */
1348 const Functions& gl = robustContext->getFunctions();
1350 /* Test result indicator */
1351 bool test_result = true;
1353 GLuint invalid_fetch_offsets[] = {
1355 512, // medium fetch
1358 GLuint fetch_offsets_count = sizeof(invalid_fetch_offsets) / sizeof(GLuint);
1359 glu::ContextType contextType = robustContext->getType();
1361 /* Iterate over all cases */
1362 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
1365 GLenum texture_target = GL_TEXTURE_2D;
1367 if (R32UI_MULTISAMPLE == m_test_case || RG8_SNORM == m_test_case)
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
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);
1383 Texture destination_texture(gl);
1384 Framebuffer framebuffer(gl);
1385 Texture source_texture(gl);
1386 Program program(gl);
1387 VertexArray vao(gl);
1390 VertexArray::Generate(gl, vao.m_id);
1391 VertexArray::Bind(gl, vao.m_id);
1393 /* Prepare textures */
1394 Texture::Generate(gl, destination_texture.m_id);
1395 Texture::Generate(gl, source_texture.m_id);
1397 if (R32UI_MULTISAMPLE == m_test_case)
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)
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.
1410 * Also, the test uses a compute shader with images
1411 * to upload the texture so max_image_samples >= 4
1414 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1415 << tcu::TestLog::EndMessage;
1421 prepareTexture(gl, false, destination_texture.m_id);
1422 prepareTexture(gl, true, source_texture.m_id);
1424 /* Select FBO settings */
1425 if (R32UI_MIPMAP == m_test_case)
1429 else if (R32UI_MULTISAMPLE == m_test_case)
1431 texture_target = GL_TEXTURE_2D_MULTISAMPLE;
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,
1440 /* Prepare valid program */
1441 program.Init("" /* cs */, getFragmentShader(contextType, true), getGeometryShader(), "" /* tcs */, "" /* tes */,
1444 /* Test valid case */
1446 Program::Use(gl, program.m_id);
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");
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)
1460 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1461 << tcu::TestLog::EndMessage;
1466 /* Enable multisampling */
1467 if (R32UI_MULTISAMPLE == m_test_case)
1469 gl.enable(GL_MULTISAMPLE);
1470 GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
1474 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1476 /* Get error from draw */
1477 GLenum error = gl.getError();
1479 /* Disable multisampling */
1480 if (R32UI_MULTISAMPLE == m_test_case)
1482 gl.disable(GL_MULTISAMPLE);
1483 GLU_EXPECT_NO_ERROR(gl.getError(), "Disable");
1486 /* Handle error from draw */
1487 GLU_EXPECT_NO_ERROR(error, "DrawArrays");
1491 if (false == verifyValidResults(gl, destination_texture.m_id))
1493 test_result = false;
1496 /* Test invalid cases */
1497 for (GLuint index = 0; index < fetch_offsets_count; ++index)
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);
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");
1513 gl.clear(GL_COLOR_BUFFER_BIT);
1514 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1515 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
1518 if (false == verifyInvalidResults(gl, destination_texture.m_id))
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;
1528 if (true == test_result)
1530 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1534 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1538 return tcu::TestNode::STOP;
1541 /** Prepares source code for fragment shader
1543 * @param is_case_valid Selects if valid or invalid case is tested
1545 * @return string with prepared code
1547 std::string TexelFetchTest::getFragmentShader(const glu::ContextType&, bool is_case_valid, GLuint fetch_offset)
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"
1556 " ivec2 point = ivec2(gs_fs_tex_coord * 16.0 + float(${OFFSET}));\n"
1557 " out_fs_color = texelFetch(uni_texture, point, ${PLANE});\n"
1560 m_specializationMap["PLANE"] = "0";
1561 m_specializationMap["SAMPLER"] = "sampler2D";
1562 m_specializationMap["TYPE"] = "vec4";
1564 if (R32UI_MIPMAP == m_test_case)
1566 m_specializationMap["PLANE"] = "1";
1567 m_specializationMap["SAMPLER"] = "usampler2D";
1568 m_specializationMap["TYPE"] = "uvec4";
1570 if (false == is_case_valid)
1573 m_specializationMap["PLANE"] = "2";
1576 else if (R32UI_MULTISAMPLE == m_test_case)
1578 m_specializationMap["PLANE"] = "9";
1579 m_specializationMap["SAMPLER"] = "usampler2DMS";
1580 m_specializationMap["TYPE"] = "uvec4";
1582 if (false == is_case_valid)
1585 m_specializationMap["PLANE"] = "gl_SampleID";
1589 std::stringstream offset;
1590 offset << fetch_offset;
1591 m_specializationMap["OFFSET"] = offset.str();
1593 return tcu::StringTemplate(source).specialize(m_specializationMap);
1596 /** Prepare shader for current test case
1600 std::string TexelFetchTest::getGeometryShader()
1602 static const GLchar* source = "${VERSION}\n"
1603 "layout(points) in;\n"
1604 "layout(triangle_strip, max_vertices = 4) out;\n"
1606 "out vec2 gs_fs_tex_coord;\n"
1610 " gs_fs_tex_coord = vec2(0, 0);\n"
1611 " gl_Position = vec4(-1, -1, 0, 1);\n"
1614 " gs_fs_tex_coord = vec2(0, 1);\n"
1615 " gl_Position = vec4(-1, 1, 0, 1);\n"
1618 " gs_fs_tex_coord = vec2(1, 0);\n"
1619 " gl_Position = vec4(1, -1, 0, 1);\n"
1622 " gs_fs_tex_coord = vec2(1, 1);\n"
1623 " gl_Position = vec4(1, 1, 0, 1);\n"
1627 return tcu::StringTemplate(source).specialize(m_specializationMap);
1630 /** Prepare shader for current test case
1634 std::string TexelFetchTest::getVertexShader()
1636 static const GLchar* source = "${VERSION}\n"
1640 " gl_Position = vec4(0, 0, 0, 1);\n"
1642 return tcu::StringTemplate(source).specialize(m_specializationMap);
1645 /** Returns name of current test case
1647 * @return Name of test case
1649 const glw::GLchar* TexelFetchTest::getTestCaseName() const
1651 const GLchar* name = "";
1653 switch (m_test_case)
1656 name = "Sampling GL_R8 texture";
1659 name = "Sampling GL_RG8_SNORM texture";
1662 name = "Sampling GL_RGBA32F texture";
1665 name = "Sampling mipmap of GL_32UI texture";
1667 case R32UI_MULTISAMPLE:
1668 name = "Sampling GL_32UI multisampled texture";
1671 TCU_FAIL("Invalid enum");
1678 /** Prepare a texture
1680 * @param is_source Selects if texutre will be used as source or destination
1681 * @param texture_id Id of texutre
1683 void TexelFetchTest::prepareTexture(const Functions& gl, bool is_source, glw::GLuint texture_id)
1686 static const GLuint image_height = 16;
1687 static const GLuint image_width = 16;
1689 /* Texture storage parameters */
1690 GLuint height = image_height;
1691 GLenum internal_format = 0;
1692 GLsizei n_levels = 1;
1693 GLenum target = GL_TEXTURE_2D;
1694 GLuint width = image_width;
1696 /* Prepare texture storage parameters */
1697 switch (m_test_case)
1700 internal_format = GL_R8;
1703 internal_format = GL_RG8_SNORM;
1706 internal_format = GL_RGBA32F;
1709 height = 2 * image_height;
1710 internal_format = GL_R32UI;
1712 width = 2 * image_width;
1714 case R32UI_MULTISAMPLE:
1715 internal_format = GL_R32UI;
1717 target = GL_TEXTURE_2D_MULTISAMPLE;
1720 TCU_FAIL("Invalid enum");
1723 /* Prepare storage */
1724 Texture::Bind(gl, texture_id, target);
1725 Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
1727 /* Set samplers to NEAREST/NEAREST if required */
1728 if (R32UI_MULTISAMPLE != m_test_case)
1730 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1731 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1734 /* Destination image can be left empty */
1735 if (false == is_source)
1737 Texture::Bind(gl, 0, target);
1741 /* Prepare texture */
1742 if (R8 == m_test_case)
1744 GLubyte source_pixels[image_width * image_height];
1745 for (GLuint i = 0; i < image_width * image_height; ++i)
1747 source_pixels[i] = static_cast<GLubyte>(i);
1750 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1751 0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
1753 else if (RG8_SNORM == m_test_case)
1755 static const GLuint n_components = 2;
1757 GLbyte source_pixels[image_width * image_height * n_components];
1758 for (GLuint i = 0; i < image_width * image_height; ++i)
1760 source_pixels[i * n_components + 0] = static_cast<GLubyte>((i % 16) - 8);
1761 source_pixels[i * n_components + 1] = static_cast<GLubyte>((i / 16) - 8);
1764 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1765 0 /* depth */, GL_RG, GL_BYTE, source_pixels);
1767 else if (RGBA32F == m_test_case)
1769 static const GLuint n_components = 4;
1771 GLfloat source_pixels[image_width * image_height * n_components];
1772 for (GLuint i = 0; i < image_width * image_height; ++i)
1774 source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
1775 source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
1776 source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
1777 source_pixels[i * n_components + 3] = 1.0f;
1780 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1781 0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
1783 else if (R32UI_MIPMAP == m_test_case)
1785 GLuint source_pixels[image_width * image_height];
1786 for (GLuint i = 0; i < image_width * image_height; ++i)
1788 source_pixels[i] = i;
1791 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
1792 0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
1794 else if (R32UI_MULTISAMPLE == m_test_case)
1796 /* Compute shader */
1797 static const GLchar* source =
1800 "layout (local_size_x = ${LOCAL_SIZE}, local_size_y = ${LOCAL_SIZE}, local_size_z = 1) in;\n"
1801 "layout (${QUALIFIER​S}) writeonly uniform highp uimage2DMS uni_image;\n"
1805 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
1806 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
1808 " imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
1809 " imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
1810 " imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
1811 " imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
1815 if (m_context_is_es)
1817 m_specializationMap["LOCAL_SIZE"] = "16";
1818 m_specializationMap["QUALIFIER​S"] = "binding = 0, r32ui";
1822 m_specializationMap["LOCAL_SIZE"] = "1";
1823 m_specializationMap["QUALIFIER​S"] = "location = 0";
1826 Program program(gl);
1827 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
1828 program.Init(cs, "", "", "", "", "");
1831 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
1832 GL_WRITE_ONLY, GL_R32UI);
1833 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1835 if (!m_context_is_es)
1837 gl.uniform1i(0 /* location */, 0 /* image unit*/);
1838 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1841 gl.dispatchCompute(16, 16, 1);
1842 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
1845 Texture::Bind(gl, 0, target);
1848 /** Verifies that texutre is filled with 0 or with (0, 0, 0, x),
1849 * where x may be 0, 1 or the biggest representable integer value.
1851 * @param texture_id Id of texture
1853 * @return true when image is filled with 0, 1 or biggest represetable integer number, false otherwise
1855 bool TexelFetchTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1857 static const GLuint height = 16;
1858 static const GLuint width = 16;
1859 static const GLuint n_pixels = height * width;
1861 // OpenGL ES has undefined out-of-bound behavior - no verification
1862 if (m_context_is_es)
1867 if (R8 == m_test_case)
1869 static const GLuint n_channels = 4;
1871 std::vector<GLubyte> pixels(n_pixels * n_channels);
1872 initPixels(pixels, n_pixels, n_channels);
1874 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1876 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
1879 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1882 for (GLuint i = 0; i < n_pixels; ++i)
1884 const GLubyte expected_red = 0;
1885 const GLubyte drawn_red = pixels[i * n_channels];
1887 if (expected_red != drawn_red)
1889 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
1890 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
1891 << tcu::TestLog::EndMessage;
1898 else if (RG8_SNORM == m_test_case)
1900 static const GLuint n_channels = 4;
1902 std::vector<GLbyte> pixels(n_pixels * n_channels);
1903 initPixels(pixels, n_pixels, n_channels);
1905 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1907 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_BYTE, &pixels[0]);
1910 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1913 for (GLuint i = 0; i < n_pixels; ++i)
1915 const GLbyte expected_red = 0;
1916 const GLbyte expected_green = 0;
1917 const GLbyte drawn_red = pixels[i * n_channels + 0];
1918 const GLbyte drawn_green = pixels[i * n_channels + 1];
1920 if ((expected_red != drawn_red) || (expected_green != drawn_green))
1922 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
1923 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
1924 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
1931 else if (RGBA32F == m_test_case)
1933 static const GLuint n_channels = 4;
1935 std::vector<GLfloat> pixels(n_pixels * n_channels);
1936 for (GLuint i = 0; i < n_pixels; ++i)
1938 const GLuint idx = i * n_channels;
1939 const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
1940 pixels[idx + 0] = value;
1941 pixels[idx + 1] = value;
1942 pixels[idx + 2] = value;
1943 pixels[idx + 3] = value;
1946 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1948 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
1951 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1954 for (GLuint i = 0; i < n_pixels; ++i)
1956 const GLfloat expected_red = 0.0f;
1957 const GLfloat expected_green = 0.0f;
1958 const GLfloat expected_blue = 0.0f;
1959 const GLfloat expected_alpha_0 =
1960 0.0f; /* OpenGL 4.5 (and ES) specifies two possiblities (0 or 1) for alpha channel (Chapter 11.1.3.12). */
1961 const GLfloat expected_alpha_1 = 1.0f;
1962 const GLfloat drawn_red = pixels[i * n_channels + 0];
1963 const GLfloat drawn_green = pixels[i * n_channels + 1];
1964 const GLfloat drawn_blue = pixels[i * n_channels + 2];
1965 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
1967 const GLfloat precision = 0.0009765625; /* (1.f / 1024.f) */
1969 if ((de::abs(expected_red - drawn_red) > precision) ||
1970 (de::abs(expected_green - drawn_green) > precision) ||
1971 (de::abs(expected_blue - drawn_blue) > precision) ||
1972 ((de::abs(expected_alpha_0 - drawn_alpha) > precision) &&
1973 (de::abs(expected_alpha_1 - drawn_alpha) > precision)))
1975 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
1976 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
1977 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha_0
1978 << " or " << expected_alpha_1 << ". At offset: " << i << tcu::TestLog::EndMessage;
1985 else if (R32UI_MIPMAP == m_test_case)
1987 static const GLuint n_channels = 4;
1989 std::vector<GLuint> pixels(n_pixels * n_channels);
1990 initPixels(pixels, n_pixels, n_channels);
1992 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1994 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1997 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2000 for (GLuint i = 0; i < n_pixels; ++i)
2002 const GLuint expected_red = 0;
2003 const GLuint drawn_red = pixels[i * n_channels];
2005 if (expected_red != drawn_red)
2007 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2008 << ". Expected value: " << expected_red << " at offset: " << i
2009 << tcu::TestLog::EndMessage;
2016 else if (R32UI_MULTISAMPLE == m_test_case)
2018 static const GLuint n_channels = 4;
2020 /* Compute shader */
2021 static const GLchar* source =
2024 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2026 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
2027 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2031 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2033 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2034 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2035 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2036 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2038 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2040 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2044 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2049 Program program(gl);
2050 Texture destination_texture(gl);
2052 Texture::Generate(gl, destination_texture.m_id);
2053 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2054 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2056 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2057 program.Init(cs, "", "", "", "", "");
2059 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2060 GL_READ_ONLY, GL_R32UI);
2061 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2062 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2063 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2064 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2066 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2067 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2069 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2070 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2072 gl.dispatchCompute(16, 16, 1);
2073 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2075 /* Pixels buffer initialization */
2076 std::vector<GLuint> pixels(n_pixels * n_channels);
2077 initPixels(pixels, n_pixels, n_channels);
2079 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2082 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2085 for (GLuint i = 0; i < n_pixels; ++i)
2087 const GLuint expected_red = 1;
2088 const GLuint drawn_red = pixels[i * n_channels];
2090 if (expected_red != drawn_red)
2092 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2093 << ". Expected value: " << expected_red << " at offset: " << i
2094 << tcu::TestLog::EndMessage;
2105 /** Verifies that texutre is filled with increasing values
2107 * @param texture_id Id of texture
2109 * @return true when image is filled with increasing values, false otherwise
2111 bool TexelFetchTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
2113 static const GLuint height = 16;
2114 static const GLuint width = 16;
2115 static const GLuint n_pixels = height * width;
2119 if (R8 == m_test_case)
2121 static const GLuint n_channels = 4;
2123 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2125 std::vector<GLubyte> pixels(n_pixels * n_channels);
2126 initPixels(pixels, n_pixels, n_channels);
2128 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
2131 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2134 for (GLuint i = 0; i < n_pixels; ++i)
2136 const GLubyte expected_red = static_cast<GLubyte>(i);
2137 const GLubyte drawn_red = pixels[i * n_channels];
2139 if (expected_red != drawn_red)
2141 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2142 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2143 << tcu::TestLog::EndMessage;
2150 else if (RG8_SNORM == m_test_case)
2152 static const GLuint n_channels = 4;
2154 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2156 std::vector<GLbyte> pixels(n_pixels * n_channels);
2157 initPixels(pixels, n_pixels, n_channels);
2159 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
2162 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2165 for (GLuint i = 0; i < n_pixels; ++i)
2167 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8);
2168 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
2169 const GLbyte drawn_red = pixels[i * n_channels + 0];
2170 const GLbyte drawn_green = pixels[i * n_channels + 1];
2172 if ((expected_red != drawn_red) || (expected_green != drawn_green))
2174 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2175 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2176 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2183 else if (RGBA32F == m_test_case)
2185 static const GLuint n_channels = 4;
2187 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2189 std::vector<GLfloat> pixels(n_pixels * n_channels);
2190 for (GLuint i = 0; i < n_pixels; ++i)
2192 const GLuint idx = i * n_channels;
2193 const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
2194 pixels[idx + 0] = value;
2195 pixels[idx + 1] = value;
2196 pixels[idx + 2] = value;
2197 pixels[idx + 3] = value;
2200 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
2203 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2206 for (GLuint i = 0; i < n_pixels; ++i)
2208 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
2209 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
2210 const GLfloat expected_blue = (GLfloat)i / 256.0f;
2211 const GLfloat expected_alpha = 1.0f;
2212 const GLuint idx = i * n_channels;
2213 const GLfloat drawn_red = pixels[idx + 0];
2214 const GLfloat drawn_green = pixels[idx + 1];
2215 const GLfloat drawn_blue = pixels[idx + 2];
2216 const GLfloat drawn_alpha = pixels[idx + 3];
2218 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2219 (expected_alpha != drawn_alpha))
2221 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2222 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2223 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2224 << ". At offset: " << i << tcu::TestLog::EndMessage;
2231 else if (R32UI_MIPMAP == m_test_case)
2233 static const GLuint n_channels = 4;
2235 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2237 std::vector<GLuint> pixels(n_pixels * n_channels, 0);
2239 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2242 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2245 for (GLuint i = 0; i < n_pixels; ++i)
2247 const GLuint expected_red = i;
2248 const GLuint drawn_red = pixels[i * n_channels];
2250 if (expected_red != drawn_red)
2252 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2253 << ". Expected value: " << expected_red << " at offset: " << i
2254 << tcu::TestLog::EndMessage;
2261 else if (R32UI_MULTISAMPLE == m_test_case)
2263 static const GLuint n_channels = 4;
2265 /* Compute shader */
2266 static const GLchar* source =
2269 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2271 "layout (location = 1, r32ui) writeonly uniform uimage2D uni_destination_image;\n"
2272 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2276 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2277 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
2279 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2280 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2281 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2282 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2284 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
2286 " imageStore(uni_destination_image, point, uvec4(1U));\n"
2290 " imageStore(uni_destination_image, point, uvec4(0U));\n"
2295 Program program(gl);
2296 Texture destination_texture(gl);
2298 Texture::Generate(gl, destination_texture.m_id);
2299 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2300 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2302 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2303 program.Init(cs, "", "", "", "", "");
2305 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2306 GL_READ_ONLY, GL_R32UI);
2307 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2308 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2309 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2310 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2312 if (!m_context_is_es)
2314 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2315 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2317 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2318 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2321 gl.dispatchCompute(16, 16, 1);
2322 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2324 /* Pixels buffer initialization */
2325 std::vector<GLuint> pixels(n_pixels * n_channels);
2326 initPixels(pixels, n_pixels, n_channels);
2328 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2332 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2335 for (GLuint i = 0; i < n_pixels; ++i)
2337 const GLuint expected_red = 1;
2338 const GLuint drawn_red = pixels[i * n_channels];
2340 if (expected_red != drawn_red)
2342 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2343 << ". Expected value: " << expected_red << " at offset: " << i
2344 << tcu::TestLog::EndMessage;
2357 * @param testCtx Test context
2358 * @param apiType Api type
2360 ImageLoadStoreTest::ImageLoadStoreTest(tcu::TestContext& testCtx, glu::ApiType apiType)
2361 : TexelFetchTest(testCtx, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded",
2368 * @return tcu::TestNode::STOP
2370 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
2372 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
2373 if (!robustContext.get())
2377 static const GLuint height = 16;
2378 static const GLuint width = 16;
2380 /* GL entry points */
2381 const Functions& gl = robustContext->getFunctions();
2383 struct FetchingOffset
2385 GLuint coord_offset;
2386 GLuint sample_offset;
2388 const FetchingOffset fetching_offsets[] = {
2389 { 16, 4 }, { 512, 4 }, { 1024, 8 }, { 2048, 8 },
2392 /* For ES start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported */
2393 if (m_context_is_es)
2394 m_test_case = RGBA32F;
2396 /* Test result indicator */
2397 bool test_result = true;
2399 /* Iterate over all cases */
2400 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
2402 /* Test case result indicator */
2403 bool case_result = true;
2405 if (R32UI_MULTISAMPLE == m_test_case)
2407 // Skip invalid program test in multi sample case
2408 // texelFetch with invalid lod plane results undefined value
2409 // OpenGL 4.5 Core Spec, around page 377
2413 /* Test case objects */
2414 Texture destination_texture(gl);
2415 Texture source_texture(gl);
2416 Program program(gl);
2418 /* Prepare textures */
2419 Texture::Generate(gl, destination_texture.m_id);
2420 Texture::Generate(gl, source_texture.m_id);
2422 if (R32UI_MULTISAMPLE == m_test_case)
2424 GLint max_integer_samples;
2425 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples);
2426 GLint max_image_samples;
2427 gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
2428 if (max_integer_samples < 4 || max_image_samples < 4)
2430 /* prepareTexture() hard-codes 4 samples (n_levels) for
2431 * R32UI_MULTISAMPLE case. This value exceeds the required
2432 * min-max value (1 in OpenGL ES 3.2) and is not supported
2433 * by all implementations.
2435 * Also, the test uses a compute shader with images
2436 * to upload the texture so max_image_samples >= 4
2439 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
2440 << tcu::TestLog::EndMessage;
2445 prepareTexture(gl, false, destination_texture.m_id);
2446 prepareTexture(gl, true, source_texture.m_id);
2448 /* Test invalid source cases */
2449 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2451 const FetchingOffset& fo = fetching_offsets[i];
2452 const std::string& cs = getComputeShader(SOURCE_INVALID, fo.coord_offset, fo.sample_offset);
2453 program.Init(cs, "", "", "", "", "");
2457 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2460 gl.dispatchCompute(width, height, 1 /* depth */);
2461 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2464 if (false == verifyInvalidResults(gl, destination_texture.m_id))
2466 case_result = false;
2470 /* Test valid case */
2471 program.Init(getComputeShader(VALID), "", "", "", "", "");
2475 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2478 gl.dispatchCompute(width, height, 1 /* depth */);
2479 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2482 if (false == verifyValidResults(gl, destination_texture.m_id))
2484 case_result = false;
2487 /* Test invalid destination cases */
2488 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2490 const FetchingOffset& fo = fetching_offsets[i];
2491 const std::string& cs = getComputeShader(DESTINATION_INVALID, fo.coord_offset, fo.sample_offset);
2492 program.Init(cs, "", "", "", "", "");
2496 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2499 gl.dispatchCompute(width, height, 1 /* depth */);
2500 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2503 if (false == verifyValidResults(gl, destination_texture.m_id))
2505 case_result = false;
2509 /* Set test result */
2510 if (false == case_result)
2512 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed"
2513 << tcu::TestLog::EndMessage;
2515 test_result = false;
2520 if (true == test_result)
2522 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2526 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2530 return tcu::TestNode::STOP;
2533 /** Prepare shader for current test case
2535 * @param version Specify which version should be prepared
2539 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset, GLuint sample_offset)
2541 static const GLchar* source =
2544 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2546 "layout (${QUALIFIER} = 1, ${FORMAT}) writeonly uniform highp ${IMAGE} uni_destination_image;\n"
2547 "layout (${QUALIFIER} = 0, ${FORMAT}) readonly uniform highp ${IMAGE} uni_source_image;\n"
2551 " ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(${DST_COORD_OFFSET}U);\n"
2552 " ivec2 point_source = ivec2(gl_WorkGroupID.xy) + ivec2(${SRC_COORD_OFFSET}U);\n"
2557 static const GLchar* copy_multisampled =
2558 " ${TYPE} color_0 = imageLoad(uni_source_image, point_source, 0 + ${SRC_SAMPLE_OFFSET});\n"
2559 " ${TYPE} color_1 = imageLoad(uni_source_image, point_source, 1 + ${SRC_SAMPLE_OFFSET});\n"
2560 " ${TYPE} color_2 = imageLoad(uni_source_image, point_source, 2 + ${SRC_SAMPLE_OFFSET});\n"
2561 " ${TYPE} color_3 = imageLoad(uni_source_image, point_source, 3 + ${SRC_SAMPLE_OFFSET});\n"
2562 " imageStore(uni_destination_image, point_destination, 0 + ${DST_SAMPLE_OFFSET}, color_0);\n"
2563 " imageStore(uni_destination_image, point_destination, 1 + ${DST_SAMPLE_OFFSET}, color_1);\n"
2564 " imageStore(uni_destination_image, point_destination, 2 + ${DST_SAMPLE_OFFSET}, color_2);\n"
2565 " imageStore(uni_destination_image, point_destination, 3 + ${DST_SAMPLE_OFFSET}, color_3);\n";
2567 static const GLchar* copy_regular = " ${TYPE} color = imageLoad(uni_source_image, point_source);\n"
2568 " imageStore(uni_destination_image, point_destination, color);\n";
2570 std::string src_coord_offset_str("0");
2571 std::string dst_coord_offset_str("0");
2572 std::string src_sample_offset_str("0");
2573 std::string dst_sample_offset_str("0");
2575 std::stringstream coord_offset_stream;
2576 coord_offset_stream << coord_offset;
2577 std::stringstream sample_offset_stream;
2578 sample_offset_stream << sample_offset;
2580 m_specializationMap["QUALIFIER"] = m_context_is_es ? "binding" : "location";
2581 m_specializationMap["IMAGE"] = "image2D";
2582 m_specializationMap["TYPE"] = "vec4";
2583 switch (m_test_case)
2586 m_specializationMap["FORMAT"] = "r8";
2589 m_specializationMap["FORMAT"] = "rg8_snorm";
2592 m_specializationMap["FORMAT"] = "rgba32f";
2595 m_specializationMap["FORMAT"] = "r32ui";
2596 m_specializationMap["IMAGE"] = "uimage2D";
2597 m_specializationMap["TYPE"] = "uvec4";
2599 case R32UI_MULTISAMPLE:
2600 m_specializationMap["FORMAT"] = "r32ui";
2601 m_specializationMap["IMAGE"] = "uimage2DMS";
2602 m_specializationMap["TYPE"] = "uvec4";
2605 TCU_FAIL("Invalid enum");
2608 m_specializationMap["SRC_COORD_OFFSET"] = "0";
2609 m_specializationMap["SRC_SAMPLE_OFFSET"] = "0";
2610 m_specializationMap["DST_COORD_OFFSET"] = "0";
2611 m_specializationMap["DST_SAMPLE_OFFSET"] = "0";
2613 if (version == SOURCE_INVALID)
2615 m_specializationMap["SRC_COORD_OFFSET"] = coord_offset_stream.str();
2616 m_specializationMap["SRC_SAMPLE_OFFSET"] = sample_offset_stream.str();
2618 else if (version == DESTINATION_INVALID)
2620 m_specializationMap["DST_COORD_OFFSET"] = coord_offset_stream.str();
2621 m_specializationMap["DST_SAMPLE_OFFSET"] = sample_offset_stream.str();
2624 const GLchar* copy = (m_test_case == R32UI_MULTISAMPLE) ? copy_multisampled : copy_regular;
2625 m_specializationMap["COPY"] = tcu::StringTemplate(copy).specialize(m_specializationMap);
2627 return tcu::StringTemplate(source).specialize(m_specializationMap);
2630 /** Set textures as images
2632 * @param id_destination Id of texture used as destination
2633 * @param id_source Id of texture used as source
2635 void ImageLoadStoreTest::setTextures(const Functions& gl, glw::GLuint id_destination, glw::GLuint id_source)
2640 switch (m_test_case)
2646 format = GL_RG8_SNORM;
2649 format = GL_RGBA32F;
2655 case R32UI_MULTISAMPLE:
2659 TCU_FAIL("Invalid enum");
2662 gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
2663 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2665 gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
2667 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2669 if (!m_context_is_es)
2671 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2672 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2674 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2675 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2679 /** Verifies that texutre is filled with 0
2681 * @param texture_id Id of texture
2683 * @return true when image is filled with 0, false otherwise
2685 bool ImageLoadStoreTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
2687 static const GLuint height = 16;
2688 static const GLuint width = 16;
2689 static const GLuint n_pixels = height * width;
2691 // OpenGL ES has undefined out-of-bound behavior - no verification
2692 if (m_context_is_es)
2695 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2696 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2700 if (R8 == m_test_case)
2702 static const GLuint n_channels = 1;
2704 std::vector<GLubyte> pixels(n_pixels * n_channels);
2705 initPixels(pixels, n_pixels, n_channels);
2707 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2709 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2712 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2715 for (GLuint i = 0; i < n_pixels; ++i)
2717 const GLubyte expected_red = 0;
2718 const GLubyte drawn_red = pixels[i];
2720 if (expected_red != drawn_red)
2722 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2723 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2724 << tcu::TestLog::EndMessage;
2731 else if (RG8_SNORM == m_test_case)
2733 static const GLuint n_channels = 2;
2735 std::vector<GLbyte> pixels(n_pixels * n_channels);
2736 initPixels(pixels, n_pixels, n_channels);
2738 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2740 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2743 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2746 for (GLuint i = 0; i < n_pixels; ++i)
2748 const GLbyte expected_red = 0;
2749 const GLbyte expected_green = 0;
2750 const GLbyte drawn_red = pixels[i * n_channels + 0];
2751 const GLbyte drawn_green = pixels[i * n_channels + 1];
2753 if ((expected_red != drawn_red) || (expected_green != drawn_green))
2755 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2756 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2757 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2764 else if (RGBA32F == m_test_case)
2766 static const GLuint n_channels = 4;
2768 std::vector<GLfloat> pixels(n_pixels * n_channels);
2769 for (GLuint i = 0; i < n_pixels; ++i)
2771 GLuint idx = i * n_channels;
2772 GLfloat value = static_cast<GLfloat>(i) / n_pixels;
2773 pixels[idx + 0] = value;
2774 pixels[idx + 1] = value;
2775 pixels[idx + 2] = value;
2776 pixels[idx + 3] = value;
2779 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2781 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
2784 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2787 for (GLuint i = 0; i < n_pixels; ++i)
2789 const GLfloat expected_red = 0.0f;
2790 const GLfloat expected_green = 0.0f;
2791 const GLfloat expected_blue = 0.0f;
2792 const GLfloat expected_alpha = 0.0f;
2793 const GLuint idx = i * n_channels;
2794 const GLfloat drawn_red = pixels[idx + 0];
2795 const GLfloat drawn_green = pixels[idx + 1];
2796 const GLfloat drawn_blue = pixels[idx + 2];
2797 const GLfloat drawn_alpha = pixels[idx + 3];
2799 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2800 (expected_alpha != drawn_alpha))
2802 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2803 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2804 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2805 << ". At offset: " << i << tcu::TestLog::EndMessage;
2812 else if (R32UI_MIPMAP == m_test_case)
2814 static const GLuint n_channels = 1;
2816 std::vector<GLuint> pixels(n_pixels * n_channels);
2817 initPixels(pixels, n_pixels, n_channels);
2819 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2821 Texture::GetData(gl, 1 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2824 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2827 for (GLuint i = 0; i < n_pixels; ++i)
2829 const GLuint expected_red = 0;
2830 const GLuint drawn_red = pixels[i];
2832 if (expected_red != drawn_red)
2834 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2835 << ". Expected value: " << expected_red << " at offset: " << i
2836 << tcu::TestLog::EndMessage;
2843 else if (R32UI_MULTISAMPLE == m_test_case)
2845 static const GLuint n_channels = 1;
2847 /* Compute shader */
2848 static const GLchar* cs = "${VERSION}\n"
2850 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2852 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
2853 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2857 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2859 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2860 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2861 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2862 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2864 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2866 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2870 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2875 Program program(gl);
2876 Texture destination_texture(gl);
2878 Texture::Generate(gl, destination_texture.m_id);
2879 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2880 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2882 program.Init(cs, "", "", "", "", "");
2884 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2885 GL_READ_ONLY, GL_R32UI);
2886 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2887 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2888 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2889 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2891 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2892 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2894 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2895 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2897 gl.dispatchCompute(16, 16, 1);
2898 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2900 /* Pixels buffer initialization */
2901 std::vector<GLuint> pixels(n_pixels * n_channels);
2902 initPixels(pixels, n_pixels, n_channels);
2904 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2907 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2910 for (GLuint i = 0; i < n_pixels; ++i)
2912 const GLuint expected_red = 1;
2913 const GLuint drawn_red = pixels[i];
2915 if (expected_red != drawn_red)
2917 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2918 << ". Expected value: " << expected_red << " at offset: " << i
2919 << tcu::TestLog::EndMessage;
2930 /** Verifies that texutre is filled with increasing values
2932 * @param texture_id Id of texture
2934 * @return true when image is filled with increasing values, false otherwise
2936 bool ImageLoadStoreTest::verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id)
2938 static const GLuint height = 16;
2939 static const GLuint width = 16;
2940 static const GLuint n_pixels = height * width;
2942 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2943 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2947 if (R8 == m_test_case)
2949 static const GLuint n_channels = 1;
2951 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2953 std::vector<GLubyte> pixels(n_pixels * n_channels);
2954 initPixels(pixels, n_pixels, n_channels);
2956 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2959 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2962 for (GLuint i = 0; i < n_pixels; ++i)
2964 const GLubyte expected_red = static_cast<GLubyte>(i);
2965 const GLubyte drawn_red = pixels[i];
2967 if (expected_red != drawn_red)
2969 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2970 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2971 << tcu::TestLog::EndMessage;
2978 else if (RG8_SNORM == m_test_case)
2980 static const GLuint n_channels = 2;
2982 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2984 std::vector<GLbyte> pixels(n_pixels * n_channels);
2985 initPixels(pixels, n_pixels, n_channels);
2987 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2990 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2993 for (GLuint i = 0; i < n_pixels; ++i)
2995 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8);
2996 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
2997 const GLbyte drawn_red = pixels[i * n_channels + 0];
2998 const GLbyte drawn_green = pixels[i * n_channels + 1];
3000 if ((expected_red != drawn_red) || (expected_green != drawn_green))
3002 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
3003 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
3004 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
3011 else if (RGBA32F == m_test_case)
3013 static const GLuint n_channels = 4;
3015 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3017 std::vector<GLfloat> pixels(n_pixels * n_channels);
3018 for (GLuint i = 0; i < n_pixels; ++i)
3020 GLfloat value = static_cast<GLfloat>(i) / n_pixels;
3021 pixels[i * n_channels + 0] = value;
3022 pixels[i * n_channels + 1] = value;
3023 pixels[i * n_channels + 2] = value;
3024 pixels[i * n_channels + 3] = value;
3027 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
3030 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3033 for (GLuint i = 0; i < n_pixels; ++i)
3035 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
3036 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
3037 const GLfloat expected_blue = (GLfloat)i / 256.0f;
3038 const GLfloat expected_alpha = 1.0f;
3039 const GLuint idx = i * n_channels;
3040 const GLfloat drawn_red = pixels[idx + 0];
3041 const GLfloat drawn_green = pixels[idx + 1];
3042 const GLfloat drawn_blue = pixels[idx + 2];
3043 const GLfloat drawn_alpha = pixels[idx + 3];
3045 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
3046 (expected_alpha != drawn_alpha))
3048 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
3049 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
3050 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
3051 << ". At offset: " << i << tcu::TestLog::EndMessage;
3058 else if (R32UI_MIPMAP == m_test_case)
3060 static const GLuint n_channels = 4;
3062 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3064 std::vector<GLuint> pixels(n_pixels * n_channels);
3065 initPixels(pixels, n_pixels, n_channels);
3067 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3070 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3073 for (GLuint i = 0; i < n_pixels; ++i)
3075 const GLuint expected_red = i;
3076 const GLuint drawn_red = pixels[i * n_channels];
3078 if (expected_red != drawn_red)
3080 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3081 << ". Expected value: " << expected_red << " at offset: " << i
3082 << tcu::TestLog::EndMessage;
3089 else if (R32UI_MULTISAMPLE == m_test_case)
3091 static const GLuint n_channels = 1;
3093 /* Compute shader */
3094 static const GLchar* cs =
3097 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3099 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
3100 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
3104 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
3105 " const uint index = gl_WorkGroupID.y * 16 + gl_WorkGroupID.x;\n"
3107 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
3108 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
3109 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
3110 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
3112 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3))))\n"
3114 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
3118 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
3123 Program program(gl);
3124 Texture destination_texture(gl);
3126 Texture::Generate(gl, destination_texture.m_id);
3127 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
3128 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
3130 program.Init(cs, "", "", "", "", "");
3132 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
3133 GL_READ_ONLY, GL_R32UI);
3134 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3135 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
3136 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
3137 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3139 gl.uniform1i(0 /* location */, 0 /* image unit*/);
3140 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3142 gl.uniform1i(1 /* location */, 1 /* image unit*/);
3143 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3145 gl.dispatchCompute(16, 16, 1);
3146 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3148 /* Pixels buffer initialization */
3149 std::vector<GLuint> pixels(n_pixels * n_channels);
3150 initPixels(pixels, n_pixels, n_channels);
3152 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3155 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3158 for (GLuint i = 0; i < n_pixels; ++i)
3160 const GLuint expected_red = 1;
3161 const GLuint drawn_red = pixels[i];
3163 if (expected_red != drawn_red)
3165 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3166 << ". Expected value: " << expected_red << " at offset: " << i
3167 << tcu::TestLog::EndMessage;
3178 /* StorageBufferTest constants */
3179 const GLfloat StorageBufferTest::m_destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3180 const GLfloat StorageBufferTest::m_source_data[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3184 * @param testCtx Test context
3185 * @param apiType Api type
3187 StorageBufferTest::StorageBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3188 : RobustnessBase(testCtx, "storage_buffer", "Verifies that out-of-bound access to SSBO is discared or resutls in 0",
3190 , m_test_case(VALID)
3192 /* Nothing to be done here */
3198 * @return tcu::TestNode::STOP
3200 tcu::TestNode::IterateResult StorageBufferTest::iterate()
3202 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3203 if (!robustContext.get())
3206 /* GL entry points */
3207 const Functions& gl = robustContext->getFunctions();
3209 /* Test result indicator */
3210 bool test_result = true;
3212 GLuint test_offsets[] = {
3214 4 * 1024, // near fetch (4K of the end of the object)
3215 1024 * 1024, // medium fetch (1MB past the end of the object)
3216 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3219 /* Iterate over all cases */
3220 while (LAST != m_test_case)
3222 /* Test case objects */
3223 Buffer destination_buffer(gl);
3224 Buffer source_buffer(gl);
3225 Program program(gl);
3227 /* Buffers initialization */
3228 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_destination_data),
3229 m_destination_data);
3230 source_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_source_data), m_source_data);
3232 destination_buffer.BindBase(0);
3233 source_buffer.BindBase(1);
3235 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3237 /* Initialize shader */
3238 const std::string& cs = getComputeShader(test_offsets[i]);
3239 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3242 /* Dispatch compute */
3243 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3244 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3246 /* Set memory barrier */
3247 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3248 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3250 /* Verify results */
3251 destination_buffer.Bind();
3252 GLfloat* buffer_data =
3253 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(m_destination_data), GL_MAP_READ_BIT);
3254 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3256 test_result &= verifyResults(buffer_data);
3258 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3259 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3263 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3267 if (true == test_result)
3269 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3273 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3277 return tcu::TestNode::STOP;
3280 /** Prepare shader for current test case
3284 std::string StorageBufferTest::getComputeShader(GLuint offset)
3286 static const GLchar* source = "${VERSION}\n"
3288 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3290 "layout (binding = 1, std430) buffer Source {\n"
3294 "layout (binding = 0, std430) buffer Destination {\n"
3300 " uint index_destination = gl_LocalInvocationID.x + ${DST_OFFSET}U;\n"
3301 " uint index_source = gl_LocalInvocationID.x + ${SRC_OFFSET}U;\n"
3303 " destination.data[index_destination] = source.data[index_source];\n"
3307 std::stringstream offset_stream;
3308 offset_stream << offset;
3310 m_specializationMap["DST_OFFSET"] = "0";
3311 m_specializationMap["SRC_OFFSET"] = "0";
3312 if (m_test_case == SOURCE_INVALID)
3313 m_specializationMap["SRC_OFFSET"] = offset_stream.str();
3314 else if (m_test_case == DESTINATION_INVALID)
3315 m_specializationMap["DST_OFFSET"] = offset_stream.str();
3317 return tcu::StringTemplate(source).specialize(m_specializationMap);
3320 /** Verify test case results
3322 * @param buffer_data Buffer data to verify
3324 * @return true if buffer_data is as expected, false othrewise
3326 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
3328 /* KHR_robust_buffer_access_behavior (and also GL 4.5 and later) states
3329 * which values can be expected when reading or writing outside of a
3330 * buffer's range. If supported, we will compare results against those
3333 * Otherwise, we will attempt to match results against previously observed
3334 * and valid behavior.
3336 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3337 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3338 static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3340 /* OpenGL ES has undefined out-of-bound behavior - verify only valid result*/
3341 if (m_context_is_es && (m_test_case != VALID))
3344 /* Prepare expected data const for proper case*/
3345 const GLchar* name = 0;
3346 bool check_expected_data = false;
3347 const GLfloat* expected_data = 0;
3348 switch (m_test_case)
3351 name = "valid indices";
3352 check_expected_data = true;
3353 expected_data = expected_data_valid;
3355 case SOURCE_INVALID:
3356 name = "invalid source indices";
3357 if (m_has_khr_robust_buffer_access)
3359 for (int b = 0; b < 4; b++)
3361 /* Each out-of-range read can either be 0 or any value within
3362 * the source buffer.
3365 if (buffer_data[b] == 0.0f)
3371 for (int c = 0; c < 4 && !valid; c++)
3373 if (buffer_data[b] == m_source_data[c])
3381 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3382 << tcu::TestLog::EndMessage;
3388 check_expected_data = true;
3389 expected_data = expected_data_invalid_source;
3392 case DESTINATION_INVALID:
3393 name = "invalid destination indices";
3394 if (m_has_khr_robust_buffer_access)
3396 for (int b = 0; b < 4; b++)
3399 /* Each out-of-range write can either be discarded (in which
3400 * case it would have the original destination value) or it
3401 * could write any value within the buffer (so we need to check
3402 * against each possible source value).
3404 if (buffer_data[b] == m_destination_data[b])
3410 for (int c = 0; c < 4 && !valid; c++)
3412 if (buffer_data[b] == m_source_data[c])
3420 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3421 << tcu::TestLog::EndMessage;
3427 check_expected_data = true;
3428 expected_data = expected_data_invalid_destination;
3432 TCU_FAIL("Invalid enum");
3435 if (check_expected_data)
3437 /* Verify buffer data */
3438 int size = static_cast<int>(sizeof(GLfloat) * 4);
3439 if (0 != memcmp(expected_data, buffer_data, size))
3441 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3442 << tcu::TestLog::EndMessage;
3452 * @param context Test context
3454 UniformBufferTest::UniformBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3455 : RobustnessBase(testCtx, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls in 0", apiType)
3456 , m_test_case(VALID)
3458 /* Nothing to be done here */
3463 * @return tcu::TestNode::STOP
3465 tcu::TestNode::IterateResult UniformBufferTest::iterate()
3467 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3468 if (!robustContext.get())
3471 static const GLfloat destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3472 /* The source buffer is packed std140 so we need vec4s */
3473 static const GLfloat source_data[16] = {
3474 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,
3477 GLuint test_offsets[] = {
3479 4 * 1024, // near fetch (4K of the end of the object)
3480 1024 * 1024, // medium fetch (1MB past the end of the object)
3481 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3484 /* GL entry points */
3485 const Functions& gl = robustContext->getFunctions();
3487 /* Test result indicator */
3488 bool test_result = true;
3490 /* Iterate over all cases */
3491 while (LAST != m_test_case)
3493 /* Test case objects */
3494 Buffer destination_buffer(gl);
3495 Buffer source_buffer(gl);
3496 Program program(gl);
3498 /* Buffers initialization */
3499 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(destination_data),
3501 source_buffer.InitData(GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, sizeof(source_data), source_data);
3503 destination_buffer.BindBase(0);
3504 source_buffer.BindBase(0);
3506 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3508 /* Initialize shader */
3509 const std::string& cs = getComputeShader(test_offsets[i]);
3510 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3513 /* Dispatch compute */
3514 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3515 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3517 /* Set memory barrier */
3518 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3519 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3521 /* Verify results */
3522 destination_buffer.Bind();
3523 GLfloat* buffer_data =
3524 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(destination_data), GL_MAP_READ_BIT);
3525 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3527 test_result &= verifyResults(buffer_data);
3529 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3530 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3534 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3538 if (true == test_result)
3540 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3544 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3548 return tcu::TestNode::STOP;
3551 /** Prepare shader for current test case
3555 std::string UniformBufferTest::getComputeShader(GLuint offset)
3557 static const GLchar* source = "${VERSION}\n"
3559 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3561 "layout (binding = 0, std140) uniform Source {\n"
3562 " float data[16];\n"
3565 "layout (binding = 0, std430) buffer Destination {\n"
3571 " uint index_destination = gl_LocalInvocationID.x;\n"
3572 " uint index_source = gl_LocalInvocationID.x + ${OFFSET}U;\n"
3574 " destination.data[index_destination] = source.data[index_source];\n"
3578 m_specializationMap["OFFSET"] = "0";
3579 if (m_test_case == SOURCE_INVALID)
3581 std::stringstream offset_stream;
3582 offset_stream << offset;
3583 m_specializationMap["OFFSET"] = offset_stream.str();
3586 return tcu::StringTemplate(source).specialize(m_specializationMap);
3589 /** Verify test case results
3591 * @param buffer_data Buffer data to verify
3593 * @return true if buffer_data is as expected, false othrewise
3595 bool UniformBufferTest::verifyResults(GLfloat* buffer_data)
3597 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3598 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3600 int size = static_cast<int>(sizeof(GLfloat) * 4);
3602 /* Prepare expected data const for proper case*/
3603 const GLfloat* expected_data = 0;
3604 const GLchar* name = 0;
3605 switch (m_test_case)
3608 expected_data = expected_data_valid;
3609 name = "valid indices";
3611 case SOURCE_INVALID:
3612 expected_data = expected_data_invalid_source;
3613 name = "invalid source indices";
3616 TCU_FAIL("Invalid enum");
3619 /* Verify buffer data */
3620 if (0 != memcmp(expected_data, buffer_data, size))
3622 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" << tcu::TestLog::EndMessage;
3628 } /* RobustBufferAccessBehavior */
3632 * @param context Rendering context.
3634 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(tcu::TestContext& testCtx, glu::ApiType apiType)
3635 : tcu::TestCaseGroup(testCtx, "robust_buffer_access_behavior",
3636 "Verifies \"robust buffer access behavior\" functionality")
3637 , m_ApiType(apiType)
3639 /* Left blank on purpose */
3642 /** Initializes a multi_bind test group.
3645 void RobustBufferAccessBehaviorTests::init(void)
3647 addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_testCtx, m_ApiType));
3648 addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_testCtx, m_ApiType));
3649 addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_testCtx, m_ApiType));
3650 addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_testCtx, m_ApiType));
3651 addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_testCtx, m_ApiType));