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