148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos/*-------------------------------------------------------------------------
248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * OpenGL Conformance Test Suite
348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * -----------------------------
448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Copyright (c) 2014-2016 The Khronos Group Inc.
648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Licensed under the Apache License, Version 2.0 (the "License");
848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * you may not use this file except in compliance with the License.
948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * You may obtain a copy of the License at
1048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
1148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *      http://www.apache.org/licenses/LICENSE-2.0
1248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
1348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Unless required by applicable law or agreed to in writing, software
1448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * distributed under the License is distributed on an "AS IS" BASIS,
1548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * See the License for the specific language governing permissions and
1748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * limitations under the License.
1848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
1984322c9402f810da3cd80b52e9f9ef72150a9004Alexander Galazin */ /*!
2048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * \file
2148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * \brief
2284322c9402f810da3cd80b52e9f9ef72150a9004Alexander Galazin */ /*-------------------------------------------------------------------*/
2348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
2448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "gl4cComputeShaderTests.hpp"
2548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "glwEnums.hpp"
2648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "glwFunctions.hpp"
2748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuMatrix.hpp"
2848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuMatrixUtil.hpp"
2948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuRenderTarget.hpp"
3048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <cmath>
3148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <cstdarg>
3248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <sstream>
3348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
3448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosnamespace gl4cts
3548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
3648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
3748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing namespace glw;
3848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::Vec2;
3948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::Vec3;
4048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::Vec4;
4148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::UVec4;
4248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::UVec3;
4348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing tcu::Mat4;
4448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
4548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosnamespace
4648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
4748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
4848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef Vec3  vec2;
4948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef Vec3  vec3;
5048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef Vec4  vec4;
5148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef UVec3 uvec3;
5248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef UVec4 uvec4;
5348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulostypedef Mat4  mat4;
5448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
5548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosconst char* const kGLSLVer = "#version 430 core\n";
5648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
5748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass ComputeShaderBase : public deqp::SubcaseBase
5848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
5948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
6048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulospublic:
6148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual ~ComputeShaderBase()
6248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
6348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
6448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
6548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ComputeShaderBase()
6648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		: renderTarget(m_context.getRenderContext().getRenderTarget()), pixelFormat(renderTarget.getPixelFormat())
6748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
6848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		float epsilon_zero = 1.f / (1 << 13);
6948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0 &&
7048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			pixelFormat.alphaBits != 0)
7148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
7248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			g_color_eps = vec4(1.f / ((float)(1 << pixelFormat.redBits) - 1.0f),
7348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							   1.f / ((float)(1 << pixelFormat.greenBits) - 1.0f),
7448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							   1.f / ((float)(1 << pixelFormat.blueBits) - 1.0f),
7548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							   1.f / ((float)(1 << pixelFormat.alphaBits) - 1.0f)) +
7648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						  vec4(epsilon_zero);
7748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
7848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0)
7948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
8048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			g_color_eps = vec4(1.f / ((float)(1 << pixelFormat.redBits) - 1.0f),
8148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							   1.f / ((float)(1 << pixelFormat.greenBits) - 1.0f),
8248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							   1.f / ((float)(1 << pixelFormat.blueBits) - 1.0f), 1.f) +
8348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						  vec4(epsilon_zero);
8448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
8548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
8648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
8748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			g_color_eps = vec4(epsilon_zero);
8848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
8948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
9048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
9148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const tcu::RenderTarget& renderTarget;
9248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const tcu::PixelFormat&  pixelFormat;
9348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	vec4					 g_color_eps;
9448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
9548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	uvec3 IndexTo3DCoord(GLuint idx, GLuint max_x, GLuint max_y)
9648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
9748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint x = idx % max_x;
9848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		idx /= max_x;
9948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint y = idx % max_y;
10048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		idx /= max_y;
10148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint z = idx;
10248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return uvec3(x, y, z);
10348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
10448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
10548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool CheckProgram(GLuint program, bool* compile_error = NULL)
10648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
10748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint compile_status = GL_TRUE;
10848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint status		 = GL_TRUE;
10948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(program, GL_LINK_STATUS, &status);
11048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
11148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (status == GL_FALSE)
11248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
11348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint attached_shaders;
11448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
11548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
11648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (attached_shaders > 0)
11748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
11848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				std::vector<GLuint> shaders(attached_shaders);
11948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
12048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
12148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				for (GLint i = 0; i < attached_shaders; ++i)
12248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
12348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLenum type;
12448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
12548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					switch (type)
12648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
12748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_VERTEX_SHADER:
128910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
129910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage;
13048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
13148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_TESS_CONTROL_SHADER:
132910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
133910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Tessellation Control Shader ***"
134910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::EndMessage;
13548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
13648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_TESS_EVALUATION_SHADER:
137910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
138910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Tessellation Evaluation Shader ***"
139910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::EndMessage;
14048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
14148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_GEOMETRY_SHADER:
142910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
143910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Geometry Shader ***" << tcu::TestLog::EndMessage;
14448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
14548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_FRAGMENT_SHADER:
146910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
147910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage;
14848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
14948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					case GL_COMPUTE_SHADER:
150910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
151910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage;
15248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
15348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					default:
154910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
155910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage;
15648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						break;
15748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
15848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
15948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLint res;
16048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
16148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (res != GL_TRUE)
16248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						compile_status = res;
16348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
16448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLint length;
16548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
16648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (length > 0)
16748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
16848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						std::vector<GLchar> source(length);
16948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						glGetShaderSource(shaders[i], length, NULL, &source[0]);
170910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
171910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage;
17248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
17348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
17448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
17548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (length > 0)
17648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
17748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						std::vector<GLchar> log(length);
17848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
179910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
180910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
18148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
18248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
18348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
18448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
18548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint length;
18648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
18748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (length > 0)
18848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
18948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				std::vector<GLchar> log(length);
19048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGetProgramInfoLog(program, length, NULL, &log[0]);
191910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
19248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
19348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
19448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
19548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (compile_error)
19648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			*compile_error = (compile_status == GL_TRUE ? false : true);
19748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (compile_status != GL_TRUE)
19848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
19948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return status == GL_TRUE ? true : false;
20048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
20148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
20248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint CreateComputeProgram(const std::string& cs)
20348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
20448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint p = glCreateProgram();
20548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
20648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!cs.empty())
20748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
20848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
20948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(p, sh);
21048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
21148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const src[2] = { kGLSLVer, cs.c_str() };
21248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 2, src, NULL);
21348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
21448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
21548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
21648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return p;
21748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
21848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
21948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint CreateProgram(const std::string& vs, const std::string& fs)
22048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
22148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint p = glCreateProgram();
22248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
22348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!vs.empty())
22448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
22548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint sh = glCreateShader(GL_VERTEX_SHADER);
22648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(p, sh);
22748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
22848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const src[2] = { kGLSLVer, vs.c_str() };
22948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 2, src, NULL);
23048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
23148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
23248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!fs.empty())
23348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
23448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
23548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(p, sh);
23648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
23748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const src[2] = { kGLSLVer, fs.c_str() };
23848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 2, src, NULL);
23948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
24048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
24148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
24248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return p;
24348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
24448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
24548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint BuildShaderProgram(GLenum type, const std::string& source)
24648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
24748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const src[2] = { kGLSLVer, source.c_str() };
24848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return glCreateShaderProgramv(type, 2, src);
24948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
25048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
25148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLfloat distance(GLfloat p0, GLfloat p1)
25248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
25348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return de::abs(p0 - p1);
25448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
25548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
25648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	inline bool ColorEqual(const vec4& c0, const vec4& c1, const vec4& epsilon)
25748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
25848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.x(), c1.x()) > epsilon.x())
25948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
26048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.y(), c1.y()) > epsilon.y())
26148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
26248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.z(), c1.z()) > epsilon.z())
26348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
26448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.w(), c1.w()) > epsilon.w())
26548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
26648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
26748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
26848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
26948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	inline bool ColorEqual(const vec3& c0, const vec3& c1, const vec4& epsilon)
27048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
27148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.x(), c1.x()) > epsilon.x())
27248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
27348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.y(), c1.y()) > epsilon.y())
27448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
27548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (distance(c0.z(), c1.z()) > epsilon.z())
27648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
27748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
27848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
27948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
28048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool ValidateReadBuffer(int x, int y, int w, int h, const vec4& expected)
28148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
28248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> display(w * h);
28348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glReadPixels(x, y, w, h, GL_RGBA, GL_FLOAT, &display[0]);
28448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
28548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int j = 0; j < h; ++j)
28648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
28748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < w; ++i)
28848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
28948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(display[j * w + i], expected, g_color_eps))
29048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
291910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
292910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Color at (" << (x + i) << ", " << (y + j) << ") is ["
293910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< display[j * w + i].x() << ", " << display[j * w + i].y() << ", " << display[j * w + i].z()
294910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< ", " << display[j * w + i].w() << "] should be [" << expected.x() << ", " << expected.y()
295910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< ", " << expected.z() << ", " << expected.w() << "]." << tcu::TestLog::EndMessage;
29648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return false;
29748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
29848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
29948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
30048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
30148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
30248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
30348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
30448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool ValidateReadBufferCenteredQuad(int width, int height, const vec3& expected)
30548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
30648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool			  result = true;
30748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec3> fb(width * height);
30848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
30948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
31048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int startx = int(((float)width * 0.1f) + 1);
31148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int starty = int(((float)height * 0.1f) + 1);
31248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int endx   = int((float)width - 2 * (((float)width * 0.1f) + 1) - 1);
31348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int endy   = int((float)height - 2 * (((float)height * 0.1f) + 1) - 1);
31448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
31548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = starty; y < endy; ++y)
31648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
31748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = startx; x < endx; ++x)
31848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
31948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
32048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], expected, g_color_eps))
32148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
32248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return false;
32348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
32448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
32548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
32648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
32748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ColorEqual(fb[2 * width + 2], vec3(0), g_color_eps))
32848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
32948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result = false;
33048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
33148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ColorEqual(fb[2 * width + (width - 3)], vec3(0), g_color_eps))
33248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
33348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result = false;
33448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
33548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ColorEqual(fb[(height - 3) * width + (width - 3)], vec3(0), g_color_eps))
33648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
33748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result = false;
33848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
33948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ColorEqual(fb[(height - 3) * width + 2], vec3(0), g_color_eps))
34048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
34148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result = false;
34248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
34348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
34448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return result;
34548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
34648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
34748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int getWindowWidth()
34848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
34948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return renderTarget.getWidth();
35048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
35148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
35248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int getWindowHeight()
35348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
35448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return renderTarget.getHeight();
35548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
35648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
35748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool ValidateWindow4Quads(const vec3& lb, const vec3& rb, const vec3& rt, const vec3& lt)
35848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
35948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int				  width  = 100;
36048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int				  height = 100;
36148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec3> fb(width * height);
36248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
36348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
36448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool status = true;
36548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
36648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// left-bottom quad
36748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = 10; y < height / 2 - 10; ++y)
36848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
36948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = 10; x < width / 2 - 10; ++x)
37048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
37148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
37248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], lb, g_color_eps))
37348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
374910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
375910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "First bad color (" << x << ", " << y << "): " << fb[idx].x() << " "
376910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
37748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
37848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
37948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
38048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
38148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// right-bottom quad
38248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = 10; y < height / 2 - 10; ++y)
38348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
38448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = width / 2 + 10; x < width - 10; ++x)
38548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
38648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
38748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], rb, g_color_eps))
38848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
389910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
390910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
391910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
39248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
39348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
39448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
39548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
39648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// right-top quad
39748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = height / 2 + 10; y < height - 10; ++y)
39848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
39948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = width / 2 + 10; x < width - 10; ++x)
40048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
40148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
40248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], rt, g_color_eps))
40348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
404910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
405910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
406910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
40748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
40848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
40948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
41048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
41148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// left-top quad
41248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = height / 2 + 10; y < height - 10; ++y)
41348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
41448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = 10; x < width / 2 - 10; ++x)
41548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
41648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
41748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], lt, g_color_eps))
41848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
419910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
420910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
421910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
42248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
42348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
42448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
42548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
42648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// middle horizontal line should be black
42748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = height / 2 - 2; y < height / 2 + 2; ++y)
42848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
42948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = 0; x < width; ++x)
43048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
43148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
43248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
43348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
434910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
435910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
436910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
43748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
43848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
43948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
44048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
44148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// middle vertical line should be black
44248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = 0; y < height; ++y)
44348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
44448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = width / 2 - 2; x < width / 2 + 2; ++x)
44548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
44648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const int idx = y * width + x;
44748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
44848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
449910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
450910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
451910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
45248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					status = false;
45348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
45448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
45548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
45648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
45748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return status;
45848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
45948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
46048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool IsEqual(vec4 a, vec4 b)
46148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
46248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
46348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
46448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
46548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool IsEqual(uvec4 a, uvec4 b)
46648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
46748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
46848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
46948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
47048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
47148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass SimpleCompute : public ComputeShaderBase
47248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
47348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
47448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
47548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
47648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Simplest possible Compute Shader";
47748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
47848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
47948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
48048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
48148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "1. Verify that CS can be created, compiled and linked.\n"
48248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "2. Verify that local work size can be queried with GetProgramiv command.\n"
48348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "3. Verify that CS can be dispatched with DispatchCompute command.\n"
48448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "4. Verify that CS can write to SSBO.";
48548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
48648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
48748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
48848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
48948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Create and dispatch CS. Verify SSBO content.";
49048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
49148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
49248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
49348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
49448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
49548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
49648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
49748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
49848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_buffer;
49948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
50048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
50148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
50248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
50348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
50448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1, local_size_y = 1) in;" NL "layout(std430) buffer Output {" NL "  vec4 data;" NL
50548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "} g_out;" NL "void main() {" NL "  g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
50648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
50748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
50848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
50948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
51048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
51148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint v[3];
51248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
51348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (v[0] != 1 || v[1] != 1 || v[2] != 1)
51448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
515910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
516910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Got " << v[0] << ", " << v[1] << ", " << v[2]
517910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< ", expected: 1, 1, 1 in GL_COMPUTE_WORK_GROUP_SIZE check" << tcu::TestLog::EndMessage;
51848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
51948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
52048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
52148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_buffer);
52248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
52348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), NULL, GL_DYNAMIC_DRAW);
52448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
52548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
52648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
52748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
52848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
52948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
53048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
53148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
53248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
53348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
53448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		vec4* data;
53548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
53648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
53748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		data	   = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
53848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		long error = NO_ERROR;
53948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
54048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
54148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			error = ERROR;
54248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
54348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
54448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
54548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return error;
54648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
54748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
54848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
54948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
55048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
55148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
55248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_buffer);
55348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
55448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
55548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
55648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
55748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicOneWorkGroup : public ComputeShaderBase
55848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
55948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
56048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
56148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
56248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "One work group with various local sizes";
56348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
56448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
56548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
56648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
56748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that declared local work size has correct effect." NL
56848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that the number of shader invocations is correct." NL
56948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that the built-in variables: gl_WorkGroupSize, gl_WorkGroupID, gl_GlobalInvocationID," NL
57048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    gl_LocalInvocationID and gl_LocalInvocationIndex has correct values." NL
57148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Verify that DispatchCompute and DispatchComputeIndirect commands work as expected.";
57248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
57348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
57448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
57548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
57648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create several CS with various local sizes." NL
57748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch each CS with DispatchCompute and DispatchComputeIndirect commands." NL
57848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify SSBO content.";
57948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
58048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
58148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
58248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
58348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
58448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
58548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
58648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
58748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
58848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
58948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
59048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(int x, int y, int z, GLuint binding)
59148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
59248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
59348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << x << ", local_size_y = " << y << ", local_size_z = " << z
59448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") in;" NL "layout(std430, binding = " << binding
59548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") buffer Output {" NL "  uvec4 local_id[];" NL "} g_out;" NL "void main() {" NL
59648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  if (gl_WorkGroupSize == uvec3("
59748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << x << ", " << y << ", " << z
59848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") && gl_WorkGroupID == uvec3(0) &&" NL "      gl_GlobalInvocationID == gl_LocalInvocationID) {" NL
59948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    g_out.local_id[gl_LocalInvocationIndex] = uvec4(gl_LocalInvocationID, 0);" NL "  } else {" NL
60048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    g_out.local_id[gl_LocalInvocationIndex] = uvec4(0xffff);" NL "  }" NL "}";
60148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
60248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
60348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
60448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(int local_size_x, int local_size_y, int local_size_z, GLuint binding, bool dispatch_indirect)
60548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
60648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
60748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
60848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size_x, local_size_y, local_size_z, binding));
60948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
61048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
61148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
61248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
61348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint v[3];
61448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
61548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (v[0] != local_size_x || v[1] != local_size_y || v[2] != local_size_z)
61648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
617910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
618910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "GL_COMPUTE_LOCAL_WORK_SIZE is (" << v[0] << " " << v[1] << " " << v[2]
619910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< ") should be (" << local_size_x << " " << local_size_y << " " << local_size_z << ")"
620910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::EndMessage;
62148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
62248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
62348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
62448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const int kSize = local_size_x * local_size_y * local_size_z;
62548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
62648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
62748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
62848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_storage_buffer);
62948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kSize, NULL, GL_DYNAMIC_DRAW);
63048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
63148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
63248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
63348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
63448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
63548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint num_groups[3] = { 1, 1, 1 };
63648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
63748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
63848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
63948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_DRAW);
64048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
64148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
64248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
64348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
64448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(1, 1, 1);
64548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
64648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
64748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		uvec4* data;
64848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
64948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
65048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		data =
65148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			static_cast<uvec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * sizeof(uvec4), GL_MAP_READ_BIT));
65248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
65348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool ret = true;
65448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
65548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int z = 0; z < local_size_z; ++z)
65648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
65748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int y = 0; y < local_size_y; ++y)
65848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
65948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				for (int x = 0; x < local_size_x; ++x)
66048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
66148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					const int index = z * local_size_x * local_size_y + y * local_size_x + x;
66248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (!IsEqual(data[index], uvec4(x, y, z, 0)))
66348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
664910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						m_context.getTestContext().getLog()
665910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							<< tcu::TestLog::Message << "Invalid data at offset " << index << tcu::TestLog::EndMessage;
66648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						ret = false;
66748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
66848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
66948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
67048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
67148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
67248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
67348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ret;
67448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
67548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
67648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
67748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
67848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
67948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
68048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
68148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
68248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
68348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
68448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
68548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
68648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(16, 1, 1, 0, true))
68748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
68848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(8, 8, 1, 1, false))
68948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
69048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(4, 4, 4, 2, true))
69148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
69248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(1, 2, 3, 3, false))
69348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
69448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(1024, 1, 1, 3, true))
69548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
69648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(16, 8, 8, 3, false))
69748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
69848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(32, 1, 32, 7, true))
69948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
70048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
70148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
70248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
70348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
70448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
70548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
70648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
70748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
70848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
70948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
71048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
71148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
71248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
71348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceUBO : public ComputeShaderBase
71448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
71548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
71648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
71748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
71848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Compute Shader resources - UBOs";
71948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
72048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
72148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
72248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
72348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Verify that CS is able to read data from UBOs and write it to SSBO.";
72448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
72548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
72648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
72748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
72848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses array of UBOs." NL
72948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
73048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Read data from each UBO and write it to SSBO." NL "4. Verify SSBO content." NL
73148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Repeat for different buffer and CS work sizes.";
73248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
73348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
73448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
73548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
73648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
73748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
73848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
73948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
74048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
74148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_uniform_buffer[12];
74248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
74348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
74448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
74548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
74648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
74748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
74848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
74948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
75048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", " << global_size.y() << ", " << global_size.z()
75148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ");" NL "layout(std140) uniform InputBuffer {" NL "  vec4 data["
75248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
75348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "} g_in_buffer[12];" NL "layout(std430) buffer OutputBuffer {" NL "  vec4 data0["
75448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data1["
75548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data2["
75648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data3["
75748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data4["
75848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data5["
75948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data6["
76048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data7["
76148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data8["
76248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data9["
76348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data10["
76448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data11["
76548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
76648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "} g_out_buffer;" NL "void main() {" NL "  const uint global_index = gl_GlobalInvocationID.x +" NL
76748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
76848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
76948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data0[global_index] = g_in_buffer[0].data[global_index];" NL
77048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data1[global_index] = g_in_buffer[1].data[global_index];" NL
77148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data2[global_index] = g_in_buffer[2].data[global_index];" NL
77248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data3[global_index] = g_in_buffer[3].data[global_index];" NL
77348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data4[global_index] = g_in_buffer[4].data[global_index];" NL
77448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data5[global_index] = g_in_buffer[5].data[global_index];" NL
77548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data6[global_index] = g_in_buffer[6].data[global_index];" NL
77648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data7[global_index] = g_in_buffer[7].data[global_index];" NL
77748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data8[global_index] = g_in_buffer[8].data[global_index];" NL
77848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data9[global_index] = g_in_buffer[9].data[global_index];" NL
77948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data10[global_index] = g_in_buffer[10].data[global_index];" NL
78048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data11[global_index] = g_in_buffer[11].data[global_index];" NL "}";
78148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
78248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
78348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
78448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
78548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
78648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
78748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
78848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
78948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
79048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
79148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
79248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
79348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 12; ++i)
79448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
79548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			char name[32];
79648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			sprintf(name, "InputBuffer[%u]", i);
79748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint index = glGetUniformBlockIndex(m_program, name);
79848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformBlockBinding(m_program, index, i);
79948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint p = 0;
80048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetActiveUniformBlockiv(m_program, index, GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER, &p);
80148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (p == GL_FALSE)
80248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
803910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
804910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
805910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
80648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
80748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
80848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
80948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
81048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize =
81148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
81248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
81348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
81448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
81548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
81648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 12, NULL, GL_DYNAMIC_DRAW);
81748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
81848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
81948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_uniform_buffer[0] == 0)
82048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(12, m_uniform_buffer);
82148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 12; ++i)
82248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
82348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(kBufferSize);
82448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint j = 0; j < kBufferSize; ++j)
82548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
82648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[j] = vec4(static_cast<float>(i * kBufferSize + j));
82748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
82848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
82948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_UNIFORM_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
83048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
83148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_UNIFORM_BUFFER, 0);
83248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
83348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
83448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
83548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
83648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
83748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
83848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
83948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
84048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
84148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
84248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
84348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
84448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
84548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
84648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
84748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> data(kBufferSize * 12);
84848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
84948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
85048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 12, &data[0]);
85148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
85248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint z = 0; z < local_size.z() * num_groups.z(); ++z)
85348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
85448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint y = 0; y < local_size.y() * num_groups.y(); ++y)
85548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
85648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				for (GLuint x = 0; x < local_size.x() * num_groups.x(); ++x)
85748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
85848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					const GLuint index = z * local_size.x() * num_groups.x() * local_size.y() * num_groups.y() +
85948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										 y * local_size.x() * num_groups.x() + x;
86048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					for (int i = 0; i < 1; ++i)
86148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
86248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						if (!IsEqual(data[index * 12 + i], vec4(static_cast<float>(index * 12 + i))))
86348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						{
864910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski							m_context.getTestContext().getLog() << tcu::TestLog::Message << "Incorrect data at offset "
865910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski																<< index * 12 + i << "." << tcu::TestLog::EndMessage;
86648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							return false;
86748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						}
86848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
86948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
87048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
87148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
87248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
87348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
87448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
87548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
87648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
87748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
87848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
87948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
88048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
88148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
88248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
88348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
88448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
88548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
88648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
88748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
88848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), true))
88948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
89048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
89148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
89248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
89348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
89448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
89548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
89648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
89748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
89848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
89948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
90048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(12, m_uniform_buffer);
90148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
90248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
90348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
90448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
90548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
90648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceTexture : public ComputeShaderBase
90748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
90848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
90948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
91048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
91148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Compute Shader resources - Textures";
91248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
91348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
91448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
91548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
91648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that texture access works correctly in CS.";
91748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
91848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
91948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
92048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
92148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses all sampler types (sampler1D, sampler2D, sampler3D, sampler2DRect," NL
92248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    sampler1DArray, sampler2DArray, samplerBuffer, sampler2DMS, sampler2DMSArray)." NL
92348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
92448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Sample each texture and write sampled value to SSBO." NL "4. Verify SSBO content." NL
92548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Repeat for different texture and CS work sizes.";
92648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
92748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
92848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
92948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
93048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
93148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
93248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
93348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
93448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
93548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture[9];
93648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture_buffer;
93748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
93848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
93948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
94048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
94148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
94248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
94348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
94448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
94548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", " << global_size.y() << ", " << global_size.z()
94648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ");" NL "uniform sampler1D g_sampler0;" NL "uniform sampler2D g_sampler1;" NL
94748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "uniform sampler3D g_sampler2;" NL "uniform sampler2DRect g_sampler3;" NL
94848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "uniform sampler1DArray g_sampler4;" NL "uniform sampler2DArray g_sampler5;" NL
94948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "uniform samplerBuffer g_sampler6;" NL "uniform sampler2DMS g_sampler7;" NL
95048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "uniform sampler2DMSArray g_sampler8;" NL "layout(std430) buffer OutputBuffer {" NL "  vec4 data0["
95148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data1["
95248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data2["
95348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data3["
95448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data4["
95548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data5["
95648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data6["
95748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data7["
95848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data8["
95948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
96048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "} g_out_buffer;" NL "void main() {" NL "  const uint global_index = gl_GlobalInvocationID.x +" NL
96148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
96248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
96348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data0[global_index] = texelFetch(g_sampler0, int(gl_GlobalInvocationID), 0);" NL
96448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data1[global_index] = texture(g_sampler1, vec2(gl_GlobalInvocationID) / "
96548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "vec2(kGlobalSize));" NL "  g_out_buffer.data2[global_index] = textureProj(g_sampler2, "
96648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "vec4(vec3(gl_GlobalInvocationID) / vec3(kGlobalSize), 1.0));" NL
96748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data3[global_index] = textureProjOffset(g_sampler3, vec3(vec2(gl_GlobalInvocationID), "
96848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "1.0), ivec2(0));" NL "  g_out_buffer.data4[global_index] = textureLodOffset(g_sampler4, "
96948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "vec2(gl_GlobalInvocationID.x / kGlobalSize.x, gl_GlobalInvocationID.y), 0.0, "
97048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "0);" NL "  g_out_buffer.data5[global_index] = texelFetchOffset(g_sampler5, "
97148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "ivec3(gl_GlobalInvocationID), 0, ivec2(0));" NL
97248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data6[global_index] = texelFetch(g_sampler6, int(global_index));" NL
97348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data7[global_index] = texelFetch(g_sampler7, ivec2(gl_GlobalInvocationID), 1);" NL
97448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.data8[global_index] = texelFetch(g_sampler8, ivec3(gl_GlobalInvocationID), 2);" NL "}";
97548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
97648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
97748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
97848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
97948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
98048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
98148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
98248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
98348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
98448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
98548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
98648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
98748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
98848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 9; ++i)
98948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
99048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			char name[32];
99148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			sprintf(name, "g_sampler%d", i);
99248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniform1i(glGetUniformLocation(m_program, name), i);
99348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
99448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
99548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
99648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize =
99748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
99848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
99948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
100048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
100148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
100248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> buffer_data(kBufferSize * 9);
100348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
100448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
100548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
100648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 9, &buffer_data[0], GL_DYNAMIC_DRAW);
100748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
100848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
100948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> texture_data(kBufferSize, vec4(123.0f));
101048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_texture[0] == 0)
101148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenTextures(9, m_texture);
101248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_texture_buffer == 0)
101348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_texture_buffer);
101448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
101548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE0);
101648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_1D, m_texture[0]);
101748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
101848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
101948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, kWidth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
102048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
102148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE1);
102248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
102348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
102448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
102548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
102648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
102748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE2);
102848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_3D, m_texture[2]);
102948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
103048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
103148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
103248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
103348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE3);
103448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_RECTANGLE, m_texture[3]);
103548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
103648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
103748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
103848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
103948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE4);
104048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_1D_ARRAY, m_texture[4]);
104148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
104248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
104348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
104448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
104548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE5);
104648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture[5]);
104748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
104848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
104948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT,
105048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 &texture_data[0]);
105148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
105248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE6);
105348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer);
105448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_TEXTURE_BUFFER, kBufferSize * sizeof(vec4), &texture_data[0], GL_DYNAMIC_DRAW);
105548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_TEXTURE_BUFFER, 0);
105648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture[6]);
105748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_texture_buffer);
105848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
105948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE7);
106048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texture[7]);
106148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA32F, kWidth, kHeight, GL_FALSE);
106248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
106348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE8);
106448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture[8]);
106548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, GL_RGBA32F, kWidth, kHeight, kDepth, GL_FALSE);
106648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
106748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// clear MS textures
106848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint fbo;
106948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenFramebuffers(1, &fbo);
107048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
107148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[7], 0);
107248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
107348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[8], 0);
107448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
107548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteFramebuffers(1, &fbo);
107648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
107748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
107848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
107948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
108048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
108148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
108248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
108348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
108448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
108548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
108648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
108748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
108848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
108948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
109048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
109148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
109248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
109348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 9, &buffer_data[0]);
109448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 0; index < kBufferSize * 9; ++index)
109548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
109648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(buffer_data[index], vec4(123.0f)))
109748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
1098910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
1099910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Incorrect data at index " << index << "." << tcu::TestLog::EndMessage;
110048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
110148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
110248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
110348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
110448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
110548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
110648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
110748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
110848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
110948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
111048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture, 0, sizeof(m_texture));
111148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_texture_buffer  = 0;
111248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
111348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
111448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
111548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
111648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
111748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
111848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(4, 4, 4), uvec3(8, 1, 1), false))
111948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
112048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), true))
112148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
112248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), false))
112348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
112448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
112548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
112648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
112748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
112848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
112948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE0);
113048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
113148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
113248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
113348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(9, m_texture);
113448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_texture_buffer);
113548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
113648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
113748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
113848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
113948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
114048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceImage : public ComputeShaderBase
114148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
114248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
114348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
114448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
114548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Compute Shader resources - Images";
114648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
114748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
114848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
114948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
115048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that reading/writing GPU memory via image variables work as expected.";
115148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
115248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
115348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
115448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
115548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses two image2D variables to read and write underlying GPU memory." NL
115648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
115748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify memory content." NL "4. Repeat for different texture and CS work sizes.";
115848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
115948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
116048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
116148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
116248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
116348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
116448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
116548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
116648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_draw_program;
116748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture[2];
116848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
116948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
117048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
117148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
117248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
117348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
117448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
117548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
117648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z()
117748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") in;" NL "layout(rgba32f) coherent uniform image2D g_image1;" NL
117848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "layout(rgba32f) uniform image2D g_image2;" NL "const uvec3 kGlobalSize = uvec3("
117948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() << ", " << global_size.y() << ", " << global_size.z()
118048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ");" NL "void main() {" NL
118148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  if (gl_GlobalInvocationID.x >= kGlobalSize.x || gl_GlobalInvocationID.y >= kGlobalSize.y) return;" NL
118248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  vec4 color = vec4(gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) / 255.0;" NL
118348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  imageStore(g_image1, ivec2(gl_GlobalInvocationID), color);" NL
118448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  vec4 c = imageLoad(g_image1, ivec2(gl_GlobalInvocationID));" NL
118548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  imageStore(g_image2, ivec2(gl_GlobalInvocationID), c);" NL "}";
118648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
118748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
118848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
118948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
119048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
119148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
119248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
119348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
119448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
119548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
119648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
119748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
119848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
119948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "g_image1"), 0);
120048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "g_image2"), 1);
120148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
120248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
120348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
120448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
120548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
120648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kSize   = kWidth * kHeight * kDepth;
120748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
120848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> data(kSize);
120948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_texture[0] == 0)
121048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenTextures(2, m_texture);
121148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
121248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 2; ++i)
121348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
121448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_texture[i]);
121548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
121648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &data[0]);
121748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
121848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, 0);
121948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
122048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
122148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
122248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
122348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
122448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
122548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
122648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
122748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
122848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
122948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
123048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
123148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
123248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
123348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
123448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
123548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
123648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
123748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
123848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE0);
123948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, m_texture[0]);
124048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE1);
124148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
124248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_draw_program);
124348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
124448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, kWidth, kHeight);
124548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
124648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
124748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> display(kWidth * kHeight);
124848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_FLOAT, &display[0]);
124948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
125048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int y = 0; y < kHeight; ++y)
125148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
125248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int x = 0; x < kWidth; ++x)
125348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
125448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (y >= getWindowHeight() || x >= getWindowWidth())
125548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
125648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					continue;
125748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
125848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const vec4 c = vec4(float(y + x) / 255.0f);
125948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(display[y * kWidth + x], c, g_color_eps))
126048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
1261910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
1262910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Got " << display[y * kWidth + x].x() << ", "
1263910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< display[y * kWidth + x].y() << ", " << display[y * kWidth + x].z() << ", "
1264910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< display[y * kWidth + x].w() << ", expected " << c.x() << ", " << c.y() << ", " << c.z()
1265910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< ", " << c.w() << " at " << x << ", " << y << tcu::TestLog::EndMessage;
126648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return false;
126748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
126848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
126948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
127048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
127148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
127248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
127348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
127448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
127548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
127648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
127748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture, 0, sizeof(m_texture));
127848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
127948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
128048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
128148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
128248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
128348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
128448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
128548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
128648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "out StageData {" NL "  vec2 texcoord;" NL "} vs_out;" NL
128748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "const vec2 g_quad[] = vec2[](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL "void main() {" NL
128848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  gl_Position = vec4(g_quad[gl_VertexID], 0, 1);" NL
128948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vs_out.texcoord = 0.5 + 0.5 * g_quad[gl_VertexID];" NL "}";
129048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
129148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* glsl_fs =
129248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "in StageData {" NL "  vec2 texcoord;" NL "} fs_in;" NL "layout(location = 0) out vec4 o_color;" NL
129348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform sampler2D g_image1;" NL "uniform sampler2D g_image2;" NL "void main() {" NL
129448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vec4 c1 = texture(g_image1, fs_in.texcoord);" NL "  vec4 c2 = texture(g_image2, fs_in.texcoord);" NL
129548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (c1 == c2) o_color = c1;" NL "  else o_color = vec4(1, 0, 0, 1);" NL "}";
129648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
129748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_draw_program = CreateProgram(glsl_vs, glsl_fs);
129848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_draw_program);
129948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_draw_program))
130048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
130148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
130248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_draw_program);
130348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_draw_program, "g_image1"), 0);
130448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_draw_program, "g_image2"), 1);
130548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
130648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
130748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
130848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
130948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!pixelFormat.alphaBits)
131048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
1311910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
1312910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Test requires default framebuffer alpha bits" << tcu::TestLog::EndMessage;
131348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return NO_ERROR;
131448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
131548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
131648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(8, 16, 1), uvec3(8, 4, 1), true))
131748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
131848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(4, 32, 1), uvec3(16, 2, 1), false))
131948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
132048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(16, 4, 1), uvec3(4, 16, 1), false))
132148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
132248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(8, 8, 1), uvec3(8, 8, 1), true))
132348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
132448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
132548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
132648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
132748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
132848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
132948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
133048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
133148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
133248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_draw_program);
133348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
133448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(2, m_texture);
133548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
133648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, getWindowWidth(), getWindowHeight());
133748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
133848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
133948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
134048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
134148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceAtomicCounter : public ComputeShaderBase
134248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
134348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
134448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
134548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
134648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Compute Shader resources - Atomic Counters";
134748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
134848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
134948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
135048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
135148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
135248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"1. Verify that Atomic Counters work as expected in CS." NL
135348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"2. Verify that built-in functions: atomicCounterIncrement and atomicCounterDecrement work correctly." NL
135448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"3. Verify that GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER is accepted by" NL
135548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    GetActiveAtomicCounterBufferiv command.";
135648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
135748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
135848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
135948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
136048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
136148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"1. Create CS which uses two atomic_uint variables." NL
136248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"2. In CS write values returned by atomicCounterIncrement and atomicCounterDecrement functions to SSBO." NL
136348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL "4. Verify SSBO content." NL
136448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"5. Repeat for different buffer and CS work sizes.";
136548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
136648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
136748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
136848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
136948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
137048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
137148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
137248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
137348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
137448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_counter_buffer[2];
137548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
137648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
137748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
137848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
137948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
138048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
138148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
138248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z()
138348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL "  uint inc_data["
138448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uint dec_data["
138548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
138648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "};" NL "layout(binding = 0, offset = 0) uniform atomic_uint g_inc_counter;" NL
138748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "layout(binding = 1, offset = 0) uniform atomic_uint g_dec_counter;" NL "void main() {" NL
138848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  const uint index = atomicCounterIncrement(g_inc_counter);" NL "  inc_data[index] = index;" NL
138948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  dec_data[index] = atomicCounterDecrement(g_dec_counter);" NL "}";
139048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
139148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
139248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
139348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
139448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
139548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
139648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
139748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
139848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
139948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
140048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
140148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
140248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint p[2] = { 0 };
140348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetActiveAtomicCounterBufferiv(m_program, 0, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[0]);
140448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetActiveAtomicCounterBufferiv(m_program, 1, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[1]);
140548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
140648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (p[0] == GL_FALSE || p[1] == GL_FALSE)
140748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
1408910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
1409910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
1410910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::EndMessage;
141148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
141248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
141348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
141448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
141548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
141648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
141748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kSize   = kWidth * kHeight * kDepth;
141848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
141948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
142048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
142148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
142248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kSize * 2, NULL, GL_DYNAMIC_DRAW);
142348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
142448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
142548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_counter_buffer[0] == 0)
142648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(2, m_counter_buffer);
142748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
142848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_counter_buffer[0]);
142948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
143048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
143148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
143248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
143348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer[1]);
143448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
143548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = kSize;
143648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
143748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
143848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
143948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
144048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
144148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
144248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
144348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
144448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
144548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
144648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
144748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
144848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
144948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
145048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
145148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
145248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
145348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
145448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLuint> data(kSize);
145548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
145648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
145748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kSize, &data[0]);
145848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
145948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < kSize; ++i)
146048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
146148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != i)
146248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
1463910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value at index " << i << " is "
1464910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
146548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
146648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
146748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
146848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
146948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint value;
147048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[0]);
147148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
147248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (value != kSize)
147348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
1474910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 0) is "
1475910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski												<< value << " should be " << kSize << "." << tcu::TestLog::EndMessage;
147648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
147748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
147848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
147948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[1]);
148048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
148148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (value != 0)
148248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
1483910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 1) is "
1484910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski												<< value << " should be 0." << tcu::TestLog::EndMessage;
148548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
148648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
148748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
148848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
148948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
149048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
149148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
149248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
149348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
149448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
149548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_counter_buffer, 0, sizeof(m_counter_buffer));
149648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
149748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
149848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
149948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
150048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
150148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
150248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(4, 3, 2), uvec3(2, 3, 4), false))
150348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
150448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 1), uvec3(1, 1, 1), true))
150548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
150648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 6, 1), uvec3(1, 1, 8), false))
150748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
150848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(4, 1, 2), uvec3(10, 3, 4), true))
150948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
151048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
151148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
151248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
151348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
151448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
151548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
151648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
151748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_counter_buffer);
151848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
151948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
152048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
152148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
152248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
152348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
152448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceSubroutine : public ComputeShaderBase
152548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
152648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
152748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
152848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
152948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Compute Shader resources - Subroutines";
153048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
153148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
153248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
153348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
153448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that subroutines work as expected in CS." NL
153548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that subroutines array can be indexed with gl_WorkGroupID built-in variable." NL
153648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that atomicCounterIncrement, imageLoad and texelFetch functions" NL
153748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    work as expected when called in CS from subroutine.";
153848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
153948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
154048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
154148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
154248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses array of subroutines." NL
154348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. In CS index subroutine array with gl_WorkGroupID built-in variable." NL
154448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. In each subroutine load data from SSBO0 and write it to SSBO1." NL
154548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
154648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Verify SSBO1 content." NL "5. Repeat for different buffer and CS work sizes.";
154748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
154848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
154948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
155048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
155148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
155248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
155348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
155448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
155548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_atomic_counter_buffer;
155648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer[2];
155748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_buffer[2];
155848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture_buffer[2];
155948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
156048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
156148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
156248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program				= 0;
156348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_atomic_counter_buffer = 0;
156448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
156548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_buffer, 0, sizeof(m_buffer));
156648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
156748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
156848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
156948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
157048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
157148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
157248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
157348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 16) in;" NL "layout(binding = 1, std430) buffer Input {" NL "  uvec4 data[16];" NL
157448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "} g_input;" NL "layout(std430, binding = 0) buffer Output {" NL "  uvec4 g_output[64];" NL "};" NL
157548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "subroutine void ComputeType();" NL "subroutine uniform ComputeType Compute[4];" NL
157648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter;" NL
157748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(rgba32ui) readonly uniform uimageBuffer g_image_buffer;" NL
157848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform usamplerBuffer g_sampler_buffer;" NL "subroutine(ComputeType)" NL "void Compute0() {" NL
157948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const uint index = atomicCounterIncrement(g_atomic_counter);" NL
158048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[index] = uvec4(index);" NL "}" NL "subroutine(ComputeType)" NL "void Compute1() {" NL
158148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[gl_GlobalInvocationID.x] = g_input.data[gl_LocalInvocationIndex];" NL "}" NL
158248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "subroutine(ComputeType)" NL "void Compute2() {" NL
158348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[gl_GlobalInvocationID.x] = imageLoad(g_image_buffer, int(gl_LocalInvocationIndex));" NL
158448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "}" NL "subroutine(ComputeType)" NL "void Compute3() {" NL
158548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[gl_GlobalInvocationID.x] = texelFetch(g_sampler_buffer, int(gl_LocalInvocationIndex));" NL
158648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "}" NL "void main() {" NL "  Compute[gl_WorkGroupID.x]();" NL "}";
158748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
158848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
158948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
159048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
159148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
159248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(2, m_storage_buffer);
159348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* output buffer */
159448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
159548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<uvec4> data(64, uvec4(0xffff));
159648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
159748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 64, &data[0], GL_DYNAMIC_DRAW);
159848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
159948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* input buffer */
160048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
160148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<uvec4> data(16);
160248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint i = 0; i < 16; ++i)
160348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[i]   = uvec4(i + 16);
160448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
160548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_DYNAMIC_DRAW);
160648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
160748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
160848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
160948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_atomic_counter_buffer);
161048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
161148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
161248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
161348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
161448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
161548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(2, m_buffer);
161648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* image buffer */
161748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
161848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<uvec4> data(16);
161948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint i = 0; i < 16; ++i)
162048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[i]   = uvec4(i + 32);
162148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[0]);
162248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
162348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
162448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* texture buffer */
162548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
162648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<uvec4> data(16);
162748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint i = 0; i < 16; ++i)
162848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[i]   = uvec4(i + 48);
162948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[1]);
163048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
163148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
163248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_TEXTURE_BUFFER, 0);
163348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
163448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenTextures(2, m_texture_buffer);
163548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[0]);
163648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[0]);
163748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
163848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[1]);
163948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, 0);
164048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
164148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute0");
164248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute1");
164348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute2");
164448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute3");
164548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute0   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[0]");
164648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute1   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[1]");
164748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute2   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[2]");
164848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute3   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[3]");
164948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
165048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// bind resources
165148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
165248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
165348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
165448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_texture_buffer[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32UI);
165548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE0);
165648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
165748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
165848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
165948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
166048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// setup subroutines
166148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint indices[4];
166248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute0] = index_compute0;
166348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute1] = index_compute1;
166448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute2] = index_compute2;
166548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute3] = index_compute3;
166648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
166748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
166848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(4, 1, 1);
166948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
167048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<uvec4> data(64);
167148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
167248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
167348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * 64, &data[0]);
167448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
167548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 64; ++i)
167648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
167748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[i], uvec4(i)))
167848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
1679910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
1680910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Invalid value at index " << i << "." << tcu::TestLog::EndMessage;
168148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
168248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
168348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
168448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
168548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint value;
168648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomic_counter_buffer);
168748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
168848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (value != 16)
168948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
1690910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value is " << value
1691910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski												<< " should be 16." << tcu::TestLog::EndMessage;
169248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
169348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
169448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
169548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
169648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
169748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
169848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
169948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
170048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
170148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
170248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_atomic_counter_buffer);
170348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_storage_buffer);
170448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_buffer);
170548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(2, m_texture_buffer);
170648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
170748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
170848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
170948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
171048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicResourceUniform : public ComputeShaderBase
171148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
171248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
171348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
171448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
171548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Compute Shader resources - Uniforms";
171648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
171748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
171848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
171948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
172048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that all types of uniform variables work as expected in CS." NL
172148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that uniform variables can be updated with Uniform* and ProgramUniform* commands." NL
172248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that re-linking CS program works as expected.";
172348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
172448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
172548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
172648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
172748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses all (single precision and integer) types of uniform variables." NL
172848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Update uniform variables with ProgramUniform* commands." NL
172948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
173048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Update uniform variables with Uniform* commands." NL
173148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "6. Verify that uniform variables were updated correctly.";
173248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
173348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
173448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
173548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
173648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
173748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
173848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
173948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
174048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
174148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
174248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
174348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
174448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
174548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
174648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
174748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
174848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
174948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
175048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
175148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs = NL
175248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout(local_size_x = 1) in;" NL "buffer Result {" NL "  int g_result;" NL "};" NL "uniform float g_0;" NL
175348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform vec2 g_1;" NL "uniform vec3 g_2;" NL "uniform vec4 g_3;" NL "uniform mat2 g_4;" NL
175448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform mat2x3 g_5;" NL "uniform mat2x4 g_6;" NL "uniform mat3x2 g_7;" NL "uniform mat3 g_8;" NL
175548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform mat3x4 g_9;" NL "uniform mat4x2 g_10;" NL "uniform mat4x3 g_11;" NL "uniform mat4 g_12;" NL
175648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform int g_13;" NL "uniform ivec2 g_14;" NL "uniform ivec3 g_15;" NL "uniform ivec4 g_16;" NL
175748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform uint g_17;" NL "uniform uvec2 g_18;" NL "uniform uvec3 g_19;" NL "uniform uvec4 g_20;" NL NL
175848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void main() {" NL "  g_result = 1;" NL NL "  if (g_0 != 1.0) g_result = 0;" NL
175948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_1 != vec2(2.0, 3.0)) g_result = 0;" NL "  if (g_2 != vec3(4.0, 5.0, 6.0)) g_result = 0;" NL
176048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_3 != vec4(7.0, 8.0, 9.0, 10.0)) g_result = 0;" NL NL
176148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_4 != mat2(11.0, 12.0, 13.0, 14.0)) g_result = 0;" NL
176248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_5 != mat2x3(15.0, 16.0, 17.0, 18.0, 19.0, 20.0)) g_result = 0;" NL
176348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_6 != mat2x4(21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0)) g_result = 0;" NL NL
176448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_7 != mat3x2(29.0, 30.0, 31.0, 32.0, 33.0, 34.0)) g_result = 0;" NL
176548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_8 != mat3(35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0)) g_result = 0;" NL
176648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_9 != mat3x4(44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0)) g_result = "
176748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"0;" NL NL "  if (g_10 != mat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
176848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_11 != mat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
176948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"0;" NL "  if (g_12 != mat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
177048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"88.0, 89.0, 90.0)) g_result = 0;" NL NL "  if (g_13 != 91) g_result = 0;" NL
177148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_14 != ivec2(92, 93)) g_result = 0;" NL "  if (g_15 != ivec3(94, 95, 96)) g_result = 0;" NL
177248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_16 != ivec4(97, 98, 99, 100)) g_result = 0;" NL NL "  if (g_17 != 101u) g_result = 0;" NL
177348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_18 != uvec2(102u, 103u)) g_result = 0;" NL
177448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_19 != uvec3(104u, 105u, 106u)) g_result = 0;" NL
177548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_20 != uvec4(107u, 108u, 109u, 110u)) g_result = 0;" NL "}";
177648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
177748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
177848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
177948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
178048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
178148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
178248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create buffer */
178348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
178448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data = 123;
178548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
178648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
178748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
178848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
178948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform1f(m_program, glGetUniformLocation(m_program, "g_0"), 1.0f);
179048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform2f(m_program, glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
179148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform3f(m_program, glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
179248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform4f(m_program, glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
179348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
179448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2 */
179548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
179648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
179748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2fv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
179848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
179948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x3 */
180048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
180148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
180248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2x3fv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
180348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
180448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x4 */
180548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
180648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
180748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2x4fv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
180848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
180948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
181048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x2 */
181148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
181248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
181348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3x2fv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
181448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
181548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3 */
181648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
181748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
181848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3fv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
181948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
182048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x4 */
182148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
182248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
182348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
182448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3x4fv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
182548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
182648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
182748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x2 */
182848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
182948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
183048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4x2fv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
183148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
183248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x3 */
183348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
183448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[12] = {
183548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
183648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			};
183748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4x3fv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
183848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
183948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4 */
184048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
184148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
184248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
184348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4fv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
184448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
184548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
184648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform1i(m_program, glGetUniformLocation(m_program, "g_13"), 91);
184748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform2i(m_program, glGetUniformLocation(m_program, "g_14"), 92, 93);
184848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform3i(m_program, glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
184948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform4i(m_program, glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
185048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
185148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform1ui(m_program, glGetUniformLocation(m_program, "g_17"), 101);
185248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform2ui(m_program, glGetUniformLocation(m_program, "g_18"), 102, 103);
185348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform3ui(m_program, glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
185448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform4ui(m_program, glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
185548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
185648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
185748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
185848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
185948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
186048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
186148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
186248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
186348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
186448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
1865910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
1866910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
186748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
186848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
186948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
187048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
187148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// re-link program (all uniforms will be set to zero)
187248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
187348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
187448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
187548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data = 123;
187648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
187748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
187848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
187948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1f(glGetUniformLocation(m_program, "g_0"), 1.0f);
188048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform2f(glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
188148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3f(glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
188248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform4f(glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
188348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
188448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2 */
188548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
188648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
188748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2fv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
188848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
188948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x3 */
189048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
189148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
189248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2x3fv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
189348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
189448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x4 */
189548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
189648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
189748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2x4fv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
189848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
189948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
190048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x2 */
190148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
190248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
190348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3x2fv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
190448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
190548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3 */
190648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
190748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
190848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3fv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
190948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
191048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x4 */
191148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
191248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
191348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
191448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3x4fv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
191548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
191648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
191748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x2 */
191848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
191948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
192048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4x2fv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
192148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
192248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x3 */
192348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
192448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[12] = {
192548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
192648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			};
192748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4x3fv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
192848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
192948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4 */
193048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
193148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
193248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
193348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4fv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
193448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
193548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
193648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "g_13"), 91);
193748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform2i(glGetUniformLocation(m_program, "g_14"), 92, 93);
193848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3i(glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
193948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform4i(glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
194048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
194148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1ui(glGetUniformLocation(m_program, "g_17"), 101);
194248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform2ui(glGetUniformLocation(m_program, "g_18"), 102, 103);
194348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
194448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform4ui(glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
194548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
194648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
194748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
194848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
194948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
195048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
195148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
195248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
195348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
195448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
1955910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
1956910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
195748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
195848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
195948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
196048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
196148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
196248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
196348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
196448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
196548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
196648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
196748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
196848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
196948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
197048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
197148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
197248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
197348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicBuiltinVariables : public ComputeShaderBase
197448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
197548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
197648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
197748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
197848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "CS built-in variables";
197948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
198048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
198148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
198248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
198348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that all (gl_WorkGroupSize, gl_WorkGroupID, gl_LocalInvocationID," NL
198448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "gl_GlobalInvocationID, gl_NumWorkGroups, gl_WorkGroupSize)" NL
198548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "CS built-in variables has correct values.";
198648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
198748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
198848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
198948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
199048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which writes all built-in variables to SSBO." NL
199148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
199248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify SSBO content." NL "4. Repeat for several different local and global work sizes.";
199348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
199448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
199548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
199648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
199748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
199848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
199948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
200048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
200148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
200248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
200348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
200448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
200548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
200648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
200748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
200848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
200948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
201048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", " << global_size.y() << ", " << global_size.z()
201148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ");" NL "layout(std430) buffer OutputBuffer {" NL "  uvec4 num_work_groups["
201248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 work_group_size["
201348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 work_group_id["
201448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 local_invocation_id["
201548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 global_invocation_id["
201648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 local_invocation_index["
201748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
201848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "} g_out_buffer;" NL "void main() {" NL
201948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  if ((gl_WorkGroupSize * gl_WorkGroupID + gl_LocalInvocationID) != gl_GlobalInvocationID) return;" NL
202048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  const uint global_index = gl_GlobalInvocationID.x +" NL
202148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
202248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
202348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.num_work_groups[global_index] = uvec4(gl_NumWorkGroups, 0);" NL
202448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.work_group_size[global_index] = uvec4(gl_WorkGroupSize, 0);" NL
202548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.work_group_id[global_index] = uvec4(gl_WorkGroupID, 0);" NL
202648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.local_invocation_id[global_index] = uvec4(gl_LocalInvocationID, 0);" NL
202748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.global_invocation_id[global_index] = uvec4(gl_GlobalInvocationID, 0);" NL
202848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_out_buffer.local_invocation_index[global_index] = uvec4(gl_LocalInvocationIndex);" NL "}";
202948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
203048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
203148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
203248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
203348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
203448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
203548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
203648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
203748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
203848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
203948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
204048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
204148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize =
204248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
204348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
204448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<uvec4> data(kBufferSize * 6);
204548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
204648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
204748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
204848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kBufferSize * 6, &data[0], GL_DYNAMIC_DRAW);
204948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
205048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
205148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
205248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
205348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
205448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
205548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
205648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
205748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
205848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
205948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
206048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
206148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
206248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
206348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
206448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
206548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
206648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
206748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * kBufferSize * 6, &data[0]);
206848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
206948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_NumWorkGroups
207048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 0; index < kBufferSize; ++index)
207148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
207248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(num_groups.x(), num_groups.y(), num_groups.z(), 0)))
207348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2074910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2075910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "gl_NumWorkGroups: Invalid data at index " << index << "."
2076910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
207748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
207848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
207948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
208048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_WorkGroupSize
208148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = kBufferSize; index < 2 * kBufferSize; ++index)
208248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
208348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(local_size.x(), local_size.y(), local_size.z(), 0)))
208448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2085910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2086910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "gl_WorkGroupSize: Invalid data at index " << index << "."
2087910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
208848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
208948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
209048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
209148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_WorkGroupID
209248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 2 * kBufferSize; index < 3 * kBufferSize; ++index)
209348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
209448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			uvec3 expected = IndexTo3DCoord(index - 2 * kBufferSize, local_size.x() * num_groups.x(),
209548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos											local_size.y() * num_groups.y());
209648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.x() /= local_size.x();
209748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.y() /= local_size.y();
209848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.z() /= local_size.z();
209948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
210048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2101910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "gl_WorkGroupID: Invalid data at index "
2102910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< index << "." << tcu::TestLog::EndMessage;
210348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
210448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
210548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
210648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_LocalInvocationID
210748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 3 * kBufferSize; index < 4 * kBufferSize; ++index)
210848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
210948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			uvec3 expected = IndexTo3DCoord(index - 3 * kBufferSize, local_size.x() * num_groups.x(),
211048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos											local_size.y() * num_groups.y());
211148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.x() %= local_size.x();
211248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.y() %= local_size.y();
211348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			expected.z() %= local_size.z();
211448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
211548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2116910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2117910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "gl_LocalInvocationID: Invalid data at index " << index << "."
2118910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
211948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
212048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
212148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
212248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_GlobalInvocationID
212348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 4 * kBufferSize; index < 5 * kBufferSize; ++index)
212448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
212548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			uvec3 expected = IndexTo3DCoord(index - 4 * kBufferSize, local_size.x() * num_groups.x(),
212648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos											local_size.y() * num_groups.y());
212748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
212848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2129910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2130910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "gl_GlobalInvocationID: Invalid data at index " << index << "."
2131910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
213248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
213348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
213448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
213548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_LocalInvocationIndex
213648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint index = 5 * kBufferSize; index < 6 * kBufferSize; ++index)
213748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
213848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			uvec3 coord = IndexTo3DCoord(index - 5 * kBufferSize, local_size.x() * num_groups.x(),
213948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										 local_size.y() * num_groups.y());
214048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint expected = (coord.x() % local_size.x()) + (coord.y() % local_size.y()) * local_size.x() +
214148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									(coord.z() % local_size.z()) * local_size.x() * local_size.y();
214248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[index], uvec4(expected)))
214348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2144910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2145910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "gl_LocalInvocationIndex: Invalid data at index " << index << "."
2146910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
214748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
214848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
214948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
215048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
215148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
215248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
215348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
215448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
215548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
215648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
215748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
215848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
215948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
216048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
216148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
216248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
216348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
216448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
216548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
216648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
216748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
216848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
216948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
217048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
217148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
217248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
217348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
217448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
217548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
217648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
217748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
217848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
217948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
218048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
218148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
218248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
218348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
218448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
218548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
218648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
218748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
218848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicMax : public ComputeShaderBase
218948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
219048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
219148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
219248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
219348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "CS max values";
219448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
219548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
219648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
219748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
219848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify (on the API and GLSL side) that all GL_MAX_COMPUTE_* values are not less than" NL
219948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "required by the OpenGL specification.";
220048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
220148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
220248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
220348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
220448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Use all API commands to query all GL_MAX_COMPUTE_* values. Verify that they are correct." NL
220548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify all gl_MaxCompute* constants in the GLSL.";
220648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
220748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
220848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
220948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
221048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
221148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
221248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
221348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
221448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_buffer;
221548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
221648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool CheckIndexed(GLenum target, const GLint* min_values)
221748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
221848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint	 i;
221948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint64   i64;
222048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLfloat   f;
222148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLdouble  d;
222248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLboolean b;
222348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
222448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint c = 0; c < 3; c++)
222548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
222648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetIntegeri_v(target, c, &i);
222748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (i < min_values[c])
222848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2229910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2230910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< min_values[c] << "." << tcu::TestLog::EndMessage;
223148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
223248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
223348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
223448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint c = 0; c < 3; c++)
223548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
223648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetInteger64i_v(target, c, &i64);
223748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (i64 < static_cast<GLint64>(min_values[c]))
223848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2239910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2240910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Is " << static_cast<GLint>(i64) << " should be at least "
2241910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< min_values[c] << "." << tcu::TestLog::EndMessage;
224248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
224348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
224448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
224548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint c = 0; c < 3; c++)
224648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
224748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetFloati_v(target, c, &f);
224848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (f < static_cast<GLfloat>(min_values[c]))
224948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2250910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2251910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Is " << static_cast<GLint>(f) << " should be at least "
2252910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< min_values[c] << "." << tcu::TestLog::EndMessage;
225348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
225448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
225548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
225648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint c = 0; c < 3; c++)
225748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
225848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetDoublei_v(target, c, &d);
225948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (d < static_cast<GLdouble>(min_values[c]))
226048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2261910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2262910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Is " << static_cast<GLint>(d) << " should be at least "
2263910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< min_values[c] << "." << tcu::TestLog::EndMessage;
226448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
226548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
226648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
226748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint c = 0; c < 3; c++)
226848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
226948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBooleani_v(target, c, &b);
227048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (b == GL_FALSE)
227148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2272910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2273910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Is GL_FALSE should be at least GL_TRUE." << tcu::TestLog::EndMessage;
227448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
227548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
227648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
227748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
227848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
227948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
228048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
228148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool Check(GLenum target, const GLint min_value)
228248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
228348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint	 i;
228448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint64   i64;
228548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLfloat   f;
228648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLdouble  d;
228748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLboolean b;
228848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
228948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(target, &i);
229048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (i < min_value)
229148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2292910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2293910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski												<< min_value << "." << tcu::TestLog::EndMessage;
229448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
229548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
229648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetInteger64v(target, &i64);
229748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLint>(i64) < min_value)
229848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2299910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2300910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Is " << static_cast<GLint>(i64) << " should be at least " << min_value
2301910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "." << tcu::TestLog::EndMessage;
230248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
230348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
230448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetFloatv(target, &f);
230548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (f < static_cast<GLfloat>(min_value))
230648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2307910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2308910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Is " << static_cast<GLint>(f) << " should be at least " << min_value << "."
2309910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::EndMessage;
231048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
231148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
231248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetDoublev(target, &d);
231348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (d < static_cast<GLdouble>(min_value))
231448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2315910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2316910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Is " << static_cast<GLint>(d) << " should be at least " << min_value << "."
2317910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::EndMessage;
231848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
231948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
232048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBooleanv(target, &b);
232148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (b != (min_value ? GL_TRUE : GL_FALSE))
232248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2323910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << b << " should be "
2324910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski												<< (min_value ? GL_TRUE : GL_FALSE) << "." << tcu::TestLog::EndMessage;
232548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
232648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
232748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
232848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
232948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
233048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
233148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
233248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
233348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
233448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_buffer  = 0;
233548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
233648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
233748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
233848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
233948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
234048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint work_group_count[3] = { 65535, 65535, 65535 };
234148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, work_group_count))
234248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
234348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
234448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint work_group_size[3] = { 1024, 1024, 64 };
234548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, work_group_size))
234648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
234748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
234848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_UNIFORM_BLOCKS, 12))
234948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
235048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 16))
235148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
235248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 8))
235348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
235448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
235548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
235648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, 32768))
235748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
235848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
235948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
236048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
236148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 1024))
236248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
236348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
236448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
236548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
236648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 512))
236748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
236848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
236948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
237048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 8))
237148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
237248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Check(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, 512))
237348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
237448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
237548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
237648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  int g_output;" NL "};" NL
237748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform ivec3 MaxComputeWorkGroupCount;" NL "uniform ivec3 MaxComputeWorkGroupSize;" NL
237848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform int MaxComputeUniformComponents;" NL "uniform int MaxComputeTextureImageUnits;" NL
237948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform int MaxComputeImageUniforms;" NL "uniform int MaxComputeAtomicCounters;" NL
238048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform int MaxComputeAtomicCounterBuffers;" NL "void main() {" NL "  g_output = 1;" NL
238148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeWorkGroupCount != gl_MaxComputeWorkGroupCount) g_output = 0;" NL
238248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeWorkGroupSize != gl_MaxComputeWorkGroupSize) g_output = 0;" NL
238348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeUniformComponents != gl_MaxComputeUniformComponents) g_output = 0;" NL
238448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeTextureImageUnits != gl_MaxComputeTextureImageUnits) g_output = 0;" NL
238548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeImageUniforms != gl_MaxComputeImageUniforms) g_output = 0;" NL
238648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeAtomicCounters != gl_MaxComputeAtomicCounters) g_output = 0;" NL
238748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (MaxComputeAtomicCounterBuffers != gl_MaxComputeAtomicCounterBuffers) g_output = 0;" NL "}";
238848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
238948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
239048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
239148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
239248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
239348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
239448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint p[3];
239548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &p[0]);
239648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &p[1]);
239748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &p[2]);
239848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3i(glGetUniformLocation(m_program, "MaxComputeWorkGroupCount"), p[0], p[1], p[2]);
239948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
240048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &p[0]);
240148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &p[1]);
240248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &p[2]);
240348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3iv(glGetUniformLocation(m_program, "MaxComputeWorkGroupSize"), 1, p);
240448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
240548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, p);
240648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "MaxComputeUniformComponents"), p[0]);
240748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
240848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, p);
240948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1iv(glGetUniformLocation(m_program, "MaxComputeTextureImageUnits"), 1, p);
241048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
241148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, p);
241248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "MaxComputeImageUniforms"), p[0]);
241348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
241448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, p);
241548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounters"), p[0]);
241648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
241748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, p);
241848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounterBuffers"), p[0]);
241948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
242048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint data = 0xffff;
242148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_buffer);
242248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
242348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint), &data, GL_DYNAMIC_DRAW);
242448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
242548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
242648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
242748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
242848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint), &data);
242948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
243048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return data == 1 ? NO_ERROR : ERROR;
243148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
243248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
243348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
243448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
243548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
243648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_buffer);
243748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
243848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
243948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
244048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
244148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicBuildMonolithic : public ComputeShaderBase
244248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
244348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
244448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
244548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
244648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Building CS monolithic program";
244748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
244848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
244948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
245048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
245148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that building monolithic CS program works as expected." NL
245248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that program consisting from 3 compilation units links as expected." NL
245348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that CS consisting from 2 strings compiles as expected.";
245448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
245548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
245648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
245748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
245848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create, compile and link CS using CreateShader, CompileShader and LinkProgram commands." NL
245948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch and verify CS program.";
246048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
246148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
246248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
246348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
246448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
246548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
246648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
246748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
246848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
246948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const cs1[2] = { "#version 430 core",
247048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
247148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									 NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL
247248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"  Run();" NL "}" };
247348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
247448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const cs2 =
247548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(binding = 0, std430) buffer Output {" NL "  vec4 g_output;" NL "};" NL
247648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"vec4 CalculateOutput();" NL "void Run() {" NL "  g_output = CalculateOutput();" NL "}";
247748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
247848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const cs3 =
247948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 0, std430) buffer Output {" NL
248048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  vec4 g_output;" NL "};" NL "vec4 CalculateOutput() {" NL "  g_output = vec4(0);" NL
248148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  return vec4(1, 2, 3, 4);" NL "}";
248248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
248348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint sh1 = glCreateShader(GL_COMPUTE_SHADER);
248448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
248548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint type;
248648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetShaderiv(sh1, GL_SHADER_TYPE, &type);
248748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLenum>(type) != GL_COMPUTE_SHADER)
248848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2489910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2490910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "SHADER_TYPE should be COMPUTE_SHADER." << tcu::TestLog::EndMessage;
249148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh1);
249248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
249348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
249448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
249548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh1, 2, cs1, NULL);
249648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh1);
249748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
249848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint sh2 = glCreateShader(GL_COMPUTE_SHADER);
249948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh2, 1, &cs2, NULL);
250048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh2);
250148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
250248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint sh3 = glCreateShader(GL_COMPUTE_SHADER);
250348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh3, 1, &cs3, NULL);
250448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh3);
250548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
250648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint p = glCreateProgram();
250748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(p, sh1);
250848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(p, sh2);
250948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(p, sh3);
251048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(p);
251148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
251248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh1);
251348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh2);
251448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh3);
251548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
251648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool res = CheckProgram(p);
251748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
251848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint buffer;
251948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &buffer);
252048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
252148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
252248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
252348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
252448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(p);
252548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
252648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
252748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		vec4 data;
252848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
252948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
253048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
253148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
253248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2533910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2534910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
253548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			res = false;
253648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
253748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
253848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &buffer);
253948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
254048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(p);
254148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
254248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return res == true ? NO_ERROR : ERROR;
254348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
254448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
254548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
254648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicBuildSeparable : public ComputeShaderBase
254748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
254848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
254948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
255048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
255148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Building CS separable program";
255248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
255348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
255448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
255548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
255648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that building separable CS program works as expected." NL
255748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that program consisting from 4 strings works as expected.";
255848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
255948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
256048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
256148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
256248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create, compile and link CS using CreateShaderProgramv command." NL
256348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch and verify CS program.";
256448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
256548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
256648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
256748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
256848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
256948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
257048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
257148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
257248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
257348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const cs[4] = {
257448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core",
257548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
257648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL "  Run();" NL "}",
257748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(binding = 0, std430) buffer Output {" NL "  vec4 g_output;" NL "};" NL
257848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "vec4 CalculateOutput();" NL "void Run() {" NL "  g_output = CalculateOutput();" NL "}",
257948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "vec4 CalculateOutput() {" NL "  g_output = vec4(0);" NL "  return vec4(1, 2, 3, 4);" NL "}"
258048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		};
258148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
258248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint p   = glCreateShaderProgramv(GL_COMPUTE_SHADER, 4, cs);
258348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool		 res = CheckProgram(p);
258448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
258548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint buffer;
258648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &buffer);
258748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
258848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
258948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
259048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
259148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(p);
259248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
259348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
259448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		vec4 data;
259548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
259648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
259748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
259848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
259948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2600910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2601910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
260248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			res = false;
260348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
260448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
260548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &vec4(0.0f)[0]);
260648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
260748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint pipeline;
260848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenProgramPipelines(1, &pipeline);
260948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, p);
261048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
261148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
261248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindProgramPipeline(pipeline);
261348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
261448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
261548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
261648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
261748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
261848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
2619910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
2620910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
262148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			res = false;
262248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
262348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
262448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgramPipelines(1, &pipeline);
262548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &buffer);
262648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(p);
262748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
262848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return res == true ? NO_ERROR : ERROR;
262948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
263048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
263148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
263248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicSharedSimple : public ComputeShaderBase
263348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
263448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
263548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
263648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Shared Memory - simple usage";
263748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
263848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
263948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
264048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
264148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that shared array of uints works as expected." NL
264248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that shared memory written by one invocation is observable by other invocations" NL
264348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    when groupMemoryBarrier() and barrier() built-in functions are used.";
264448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
264548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
264648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
264748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
264848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
264948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify results written by CS to SSBO." NL
265048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Repeat for several different number of work groups.";
265148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
265248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
265348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
265448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
265548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
265648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
265748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
265848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
265948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
266048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
266148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
266248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const GLuint num_groups, bool dispatch_indirect)
266348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
266448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize = 256 * num_groups;
266548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
266648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLuint> data(kBufferSize, 0xffff);
266748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
266848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
266948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
267048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
267148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
267248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
267348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
267448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
267548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
267648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint groups[3] = { num_groups, 1, 1 };
267748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
267848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
267948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
268048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
268148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
268248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
268348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
268448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
268548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups, 1, 1);
268648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
268748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
268848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
268948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
269048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &data[0]);
269148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < kBufferSize; ++i)
269248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
269348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != 1)
269448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2695910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2696910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< data[i] << " should be 1." << tcu::TestLog::EndMessage;
269748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
269848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
269948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
270048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
270148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
270248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
270348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
270448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
270548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
270648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
270748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
270848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
270948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
271048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
271148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
271248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
271348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
271448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 256) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
271548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "shared uint g_shared_data[256];" NL "void main() {" NL
271648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shared_data[gl_LocalInvocationID.x] = gl_LocalInvocationIndex;" NL
271748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  groupMemoryBarrier();" // flush memory stores
271848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  barrier();"			 // wait for all stores to finish
271948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  g_output[gl_GlobalInvocationID.x] = 1;" NL "  if (gl_LocalInvocationIndex < 255) {" NL
272048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    const uint res = g_shared_data[gl_LocalInvocationID.x + "
272148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "1];" // load data from shared memory filled by other thread
272248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "    if (res != (gl_LocalInvocationIndex + 1)) {" NL "      g_output[gl_GlobalInvocationID.x] = 0;" NL
272348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    }" NL "  }" NL "}";
272448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
272548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
272648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
272748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
272848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
272948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(1, false))
273048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
273148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(8, true))
273248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
273348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(13, false))
273448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
273548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(7, true))
273648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
273748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
273848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
273948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
274048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
274148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
274248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
274348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
274448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
274548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
274648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
274748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
274848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
274948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicSharedStruct : public ComputeShaderBase
275048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
275148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
275248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
275348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Shared Memory - arrays and structers";
275448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
275548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
275648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
275748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
275848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that vectors, matrices, structers and arrays of those can be used" NL
275948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    as a shared memory." NL
276048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that shared memory can be indexed with constant values, built-in" NL
276148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    variables and dynamic expressions." NL
276248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that memoryBarrierAtomicCounter(), memoryBarrierImage(), memoryBarrier()," NL
276348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "     memoryBarrierBuffer() and memoryBarrierShared() built-in functions are accepted" NL
276448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "     by the GLSL compiler.";
276548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
276648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
276748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
276848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
276948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
277048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify results written by CS to SSBO.";
277148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
277248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
277348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
277448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
277548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return "Everything works as expected.";
277648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
277748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
277848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
277948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
278048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
278148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
278248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(bool dispatch_indirect)
278348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
278448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize = 256;
278548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
278648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<vec4> data(kBufferSize);
278748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
278848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
278948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
279048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
279148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
279248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
279348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
279448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
279548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
279648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint groups[3] = { 1, 1, 1 };
279748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
279848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
279948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
280048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
280148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
280248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
280348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
280448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
280548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(1, 1, 1);
280648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
280748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
280848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
280948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
281048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize, &data[0]);
281148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < kBufferSize; ++i)
281248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
281348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!IsEqual(data[i], vec4(static_cast<float>(i))))
281448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2815910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
2816910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
281748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
281848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
281948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
282048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
282148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
282248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
282348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
282448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
282548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
282648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
282748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
282848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
282948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
283048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
283148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
283248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
283348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs = NL
283448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout(local_size_x = 128) in;" NL "layout(std430) buffer Output {" NL "  vec4 g_output[256];" NL "};" NL
283548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"struct SubData {" NL "  mat2x4 data;" NL "};" NL "struct Data {" NL "  uint index;" NL "  vec3 data0;" NL
283648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  SubData data1;" NL "};" NL "shared Data g_shared_data[256];" NL "shared int g_shared_buf[2];" NL
283748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void main() {" NL "  if (gl_LocalInvocationID.x == 0) {" NL "    g_shared_buf[1] = 1;" NL
283848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_shared_buf[1 + gl_LocalInvocationID.x] = 0;" NL "    g_shared_buf[0] = 128;" NL
283948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_output[0] = vec4(g_shared_buf[1]);" NL "    g_output[128] = vec4(g_shared_buf[0]);" NL
284048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    memoryBarrierBuffer();" // note: this call is not needed here, just check if compiler accepts it
284148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  } else {" NL "    const uint index = gl_LocalInvocationIndex;" NL
284248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_shared_data[index].index = index;" NL "    g_shared_data[index + 128].index = index + 128;" NL
284348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_shared_data[index].data1.data = mat2x4(0.0);" NL
284448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_shared_data[index + 128].data1.data = mat2x4(0.0);" NL
284548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    g_output[index] = vec4(g_shared_data[index].index);" // load data from shared memory
284648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "    g_output[index + 128] = vec4(g_shared_data[index + 128].index);" NL
284748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    memoryBarrierShared();" // note: this call is not needed here, just check if compiler accepts it
284848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  }" NL "  memoryBarrierAtomicCounter();" NL "  memoryBarrierImage();" NL
284948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  memoryBarrier();" // note: these calls are not needed here, just check if compiler accepts them
285048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "}";
285148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
285248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
285348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
285448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
285548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
285648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(false))
285748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
285848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(true))
285948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
286048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
286148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
286248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
286348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
286448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
286548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
286648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
286748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
286848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
286948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
287048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
287148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
287248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
287348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicDispatchIndirect : public ComputeShaderBase
287448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
287548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
287648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
287748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "DispatchComputeIndirect command";
287848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
287948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
288048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
288148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
288248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
288348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"1. Verify that DispatchComputeIndirect command works as described in the OpenGL specification." NL
288448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"2. Verify that <offset> parameter is correctly applied." NL
288548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"3. Verify that updating dispatch buffer with different methods (BufferData, BufferSubData, MapBuffer)" NL
288648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    just before DispatchComputeIndirect call works as expected." NL
288748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"4. Verify that GL_DISPATCH_INDIRECT_BUFFER_BINDING binding point is set correctly.";
288848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
288948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
289048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
289148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
289248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
289348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"1. Create CS and dispatch indirect buffer." NL "2. Dispatch CS with DispatchComputeIndirect command." NL
289448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"3. Update dispatch indirect buffer." NL
289548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"4. Repeat several times updating dispatch buffer with different methods and changing <offset> parameter.";
289648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
289748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
289848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
289948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
290048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
290148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
290248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
290348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
290448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
290548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer[2];
290648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
290748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(GLintptr offset, GLuint buffer_size)
290848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
290948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLuint> data(buffer_size);
291048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
291148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
291248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
291348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * buffer_size, &data[0], GL_DYNAMIC_DRAW);
291448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
291548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(offset);
291648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
291748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
291848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * buffer_size, &data[0]);
291948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < buffer_size; ++i)
292048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
292148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != i)
292248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
2923910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2924910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
292548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
292648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
292748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
292848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
292948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
293048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
293148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool CheckBinding(GLuint expected)
293248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
293348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint	 i;
293448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint64   i64;
293548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLfloat   f;
293648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLdouble  d;
293748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLboolean b;
293848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
293948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i);
294048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLuint>(i) != expected)
294148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
294248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
294348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
294448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetInteger64v(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i64);
294548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLuint>(i64) != expected)
294648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
294748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
294848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
294948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetFloatv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &f);
295048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLuint>(f) != expected)
295148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
295248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
295348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
295448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetDoublev(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &d);
295548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (static_cast<GLuint>(d) != expected)
295648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
295748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
295848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
295948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBooleanv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &b);
296048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (b != (expected != 0 ? GL_TRUE : GL_FALSE))
296148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
296248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
296348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
296448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
296548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
296648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
296748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
296848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
296948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
297048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
297148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
297248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
297348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
297448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
297548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
297648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
297748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
297848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
297948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
298048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform uvec3 g_global_size;" NL "void main() {" NL
298148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const uint global_index = gl_GlobalInvocationID.x +" NL
298248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "                            gl_GlobalInvocationID.y * g_global_size.x +" NL
298348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "                            gl_GlobalInvocationID.z * g_global_size.x * g_global_size.y;" NL
298448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (gl_NumWorkGroups != g_global_size) {" NL "    g_output[global_index] = 0xffff;" NL
298548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    return;" NL "  }" NL "  g_output[global_index] = global_index;" NL "}";
298648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
298748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
298848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
298948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
299048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
299148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckBinding(0))
299248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
299348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
299448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(2, m_dispatch_buffer);
299548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
299648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint data[]  = { 1, 2, 3, 4, 5, 6, 7, 8 };
299748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint data2[] = { 3, 1, 4, 4 };
299848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
299948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
300048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
300148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckBinding(m_dispatch_buffer[0]))
300248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
300348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
300448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
300548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data2), data2, GL_STREAM_READ);
300648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckBinding(m_dispatch_buffer[1]))
300748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
300848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
300948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
301048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
301148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
301248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
301348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(0, 6))
301448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
301548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
301648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 2, 3, 4);
301748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(4, 24))
301848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
301948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
302048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 5, 6);
302148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(12, 120))
302248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
302348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
302448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferSubData(GL_DISPATCH_INDIRECT_BUFFER, 20, 12, data);
302548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
302648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(20, 6))
302748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
302848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
302948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint* ptr = static_cast<GLuint*>(glMapBuffer(GL_DISPATCH_INDIRECT_BUFFER, GL_WRITE_ONLY));
303048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*ptr++		= 4;
303148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*ptr++		= 4;
303248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		*ptr++		= 4;
303348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_DISPATCH_INDIRECT_BUFFER);
303448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
303548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 4, 4);
303648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(0, 64))
303748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
303848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
303948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
304048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
304148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 4, 4);
304248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(4, 16))
304348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
304448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
304548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_dispatch_buffer);
304648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
304748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
304848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckBinding(0))
304948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
305048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
305148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
305248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
305348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
305448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
305548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
305648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
305748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
305848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_dispatch_buffer);
305948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
306048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
306148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
306248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
306348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicSSOComputePipeline : public ComputeShaderBase
306448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
306548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
306648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
306748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Separable CS Programs - Compute and non-compute stages (1)";
306848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
306948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
307048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
307148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that compute and non-compute stages can be attached to one pipeline object." NL
307248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that DrawArrays and ComputeDispatch commands works as expected in this case.";
307348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
307448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
307548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
307648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
307748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
307848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Issue MemoryBarrier command." NL
307948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Issue DrawArrays command which uses data written by the compute stage." NL "6. Verify result.";
308048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
308148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
308248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
308348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
308448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
308548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
308648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vsp, m_fsp, m_csp;
308748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
308848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
308948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_pipeline;
309048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
309148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
309248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
309348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vsp = m_fsp = m_csp = 0;
309448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer	  = 0;
309548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array		  = 0;
309648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_pipeline			  = 0;
309748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
309848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
309948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
310048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
310148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
310248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 4) in;" NL "layout(std430) buffer Output {" NL "  vec4 g_output[4];" NL "};" NL
310348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  const vec2 quad[4] = { vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1) };" NL
310448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[gl_GlobalInvocationID.x] = vec4(quad[gl_GlobalInvocationID.x], 0, 1);" NL "}";
310548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
310648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_csp = CreateComputeProgram(glsl_cs);
310748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramParameteri(m_csp, GL_PROGRAM_SEPARABLE, GL_TRUE);
310848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_csp);
310948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_csp))
311048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
311148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
311248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
311348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 i_position;" NL "out gl_PerVertex {" NL "  vec4 gl_Position;" NL "};" NL
311448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  gl_Position = i_position;" NL "}";
311548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, glsl_vs);
311648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_vsp))
311748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
311848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
311948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
312048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL "  o_color = vec4(0, 1, 0, 1);" NL "}";
312148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_fsp = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs);
312248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_fsp))
312348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
312448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
312548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenProgramPipelines(1, &m_pipeline);
312648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_vsp);
312748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_fsp);
312848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_csp);
312948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
313048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
313148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
313248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * 4, NULL, GL_DYNAMIC_DRAW);
313348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
313448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
313548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
313648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
313748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, m_storage_buffer);
313848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
313948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, 0);
314048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(0);
314148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(0);
314248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
314348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindProgramPipeline(m_pipeline);
314448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
314548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
314648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
314748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
314848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
314948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
315048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
315148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
315248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
315348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
315448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
315548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
315648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
315748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
315848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
315948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_vsp);
316048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_fsp);
316148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_csp);
316248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
316348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
316448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgramPipelines(1, &m_pipeline);
316548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
316648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
316748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
316848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
316948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicSSOCase2 : public ComputeShaderBase
317048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
317148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
317248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
317348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Separable CS Programs - Compute and non-compute stages (2)";
317448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
317548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
317648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
317748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that data computed by the compute stage is visible to non-compute stage after "
317848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "MemoryBarrier command." NL "2. Verify that ProgramParameteri(program, GL_PROGRAM_SEPARABLE, "
317948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "GL_TRUE) command works correctly for CS." NL
318048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that gl_WorkGroupSize built-in variable is a contant and can be used as an array size.";
318148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
318248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
318348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
318448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
318548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
318648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Issue MemoryBarrier command." NL
318748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Issue DrawArrays command which uses data written to the buffer object by the compute stage." NL
318848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "6. Verify result.";
318948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
319048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
319148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
319248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
319348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
319448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
319548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_ab;
319648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_c;
319748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_pipeline;
319848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
319948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vao;
320048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
320148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
320248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
320348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_ab	 = 0;
320448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_c		 = 0;
320548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_pipeline		 = 0;
320648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
320748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vao			 = 0;
320848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
320948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
321048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
321148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
321248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint res;
321348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
321448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (res <= 0)
321548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
321648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
321748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return NO_ERROR;
321848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
321948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
322048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_a =
322148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(binding = 1, std430) buffer Input {" NL "  vec2 g_input[4];" NL "};" NL
322248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"out StageData {" NL "  vec3 color;" NL "} g_vs_out;" NL "out gl_PerVertex {" NL "  vec4 gl_Position;" NL
322348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"};" NL "void main() {" NL "  gl_Position = vec4(g_input[gl_VertexID], 0, 1);" NL
322448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  g_vs_out.color = vec3(0, 1, 0);" NL "}";
322548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
322648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_b =
322748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "in StageData {" NL "  vec3 color;" NL "} g_fs_in;" NL
322848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(g_fs_in.color, 1);" NL "}";
322948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
323048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_c =
323148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(local_size_x = 4) in;" NL "layout(binding = 1, std430) buffer Output {" NL
323248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  vec2 g_output[gl_WorkGroupSize.x];" NL "};" NL "void main() {" NL
323348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (gl_GlobalInvocationID.x == 0) {" NL "    g_output[0] = vec2(-0.8, -0.8);" NL
323448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  } else if (gl_GlobalInvocationID.x == 1) {" NL "    g_output[1] = vec2(0.8, -0.8);" NL
323548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  } else if (gl_GlobalInvocationID.x == 2) {" NL "    g_output[2] = vec2(-0.8, 0.8);" NL
323648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  } else if (gl_GlobalInvocationID.x == 3) {" NL "    g_output[3] = vec2(0.8, 0.8);" NL "  }" NL "}";
323748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
323848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_ab = glCreateProgram();
323948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint sh	= glCreateShader(GL_VERTEX_SHADER);
324048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(m_program_ab, sh);
324148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
324248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &glsl_a, NULL);
324348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
324448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
324548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		sh = glCreateShader(GL_FRAGMENT_SHADER);
324648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(m_program_ab, sh);
324748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
324848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &glsl_b, NULL);
324948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
325048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
325148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramParameteri(m_program_ab, GL_PROGRAM_SEPARABLE, GL_TRUE);
325248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program_ab);
325348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
325448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_c = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_c);
325548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vao);
325648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenProgramPipelines(1, &m_pipeline);
325748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_ab);
325848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_c);
325948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
326048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
326148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer);
326248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec2) * 4, NULL, GL_STREAM_DRAW);
326348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
326448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
326548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindProgramPipeline(m_pipeline);
326648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
326748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
326848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vao);
326948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
327048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
327148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (getWindowWidth() < 500 &&
327248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			!ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
327348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
327448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
327548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
327648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
327748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
327848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
327948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
328048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_ab);
328148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_c);
328248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgramPipelines(1, &m_pipeline);
328348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
328448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vao);
328548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
328648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
328748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
328848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
328948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicSSOCase3 : public ComputeShaderBase
329048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
329148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
329248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
329348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Separable CS Programs - Compute stage";
329448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
329548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
329648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
329748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that compute shader stage selected with UseProgram command has precedence" NL
329848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "over compute shader stage selected with BindProgramPipeline command.";
329948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
330048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
330148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
330248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS0 with CreateProgram command. Create CS1 with CreateShaderProgramv command." NL
330348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that CS program selected with UseProgram is dispatched even if there is active" NL
330448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    compute stage bound by BindProgramPipeline.";
330548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
330648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
330748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
330848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
330948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
331048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
331148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_a;
331248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_b;
331348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_pipeline;
331448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
331548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
331648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
331748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
331848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_a		 = 0;
331948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_b		 = 0;
332048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_pipeline		 = 0;
332148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
332248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
332348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
332448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
332548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
332648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_a =
332748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
332848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  int g_output;" NL "};" NL "void main() {" NL "  g_output = 1;" NL "}";
332948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
333048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_b =
333148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
333248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  int g_output;" NL "};" NL "void main() {" NL "  g_output = 2;" NL "}";
333348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
333448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create program A */
333548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
333648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			m_program_a = glCreateProgram();
333748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint sh   = glCreateShader(GL_COMPUTE_SHADER);
333848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(m_program_a, sh);
333948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
334048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 1, &glsl_a, NULL);
334148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
334248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramParameteri(m_program_a, GL_PROGRAM_SEPARABLE, GL_TRUE);
334348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glLinkProgram(m_program_a);
334448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
334548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_b = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_b);
334648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
334748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create storage buffer */
334848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
334948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data = 0;
335048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
335148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer);
335248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), &data, GL_STREAM_READ);
335348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
335448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
335548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenProgramPipelines(1, &m_pipeline);
335648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_b);
335748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
335848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program_a);
335948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindProgramPipeline(m_pipeline);
336048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
336148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
336248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
336348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
336448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
336548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
336648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
336748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
336848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3369910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
3370910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
337148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
337248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
337348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
337448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
337548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
337648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
337748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
337848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
337948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
338048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
338148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
338248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
338348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 2)
338448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3385910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
3386910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
338748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
338848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
338948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
339048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
339148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program_b);
339248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
339348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
339448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
339548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
339648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
339748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
339848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
339948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 2)
340048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3401910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
3402910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
340348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
340448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
340548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
340648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
340748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
340848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_a);
340948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
341048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
341148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
341248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
341348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
341448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
341548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
341648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
341748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3418910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
3419910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
342048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
342148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
342248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
342348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
342448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
342548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
342648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
342748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
342848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_a);
342948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_b);
343048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgramPipelines(1, &m_pipeline);
343148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
343248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
343348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
343448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
343548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
343648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicAtomicCase1 : public ComputeShaderBase
343748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
343848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
343948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
344048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Atomic functions";
344148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
344248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
344348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
344448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that atomicAdd function works as expected with int and uint parameters." NL
344548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that shared memory can be used with atomic functions." NL
344648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that groupMemoryBarrier() and barrier() built-in functions work as expected.";
344748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
344848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
344948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
345048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Use shared memory as a 'counter' with-in one CS work group." NL
345148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Each shader invocation increments/decrements 'counter' value using atomicAdd function." NL
345248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Values returned by atomicAdd function are written to SSBO." NL
345348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Verify SSBO content (values from 0 to 7 should be written).";
345448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
345548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
345648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
345748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
345848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
345948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
346048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
346148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
346248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
346348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
346448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
346548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
346648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
346748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
346848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
346948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
347048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
347148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
347248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 8) in;" NL "layout(std430, binding = 0) buffer Output {" NL
347348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint g_add_output[8];" NL "  int g_sub_output[8];" NL "};" NL "shared uint g_add_value;" NL
347448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "shared int g_sub_value;" NL "void main() {" NL "  if (gl_LocalInvocationIndex == 0) {" NL
347548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_add_value = 0u;" NL "    g_sub_value = 7;" NL "  }" NL
347648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_add_output[gl_LocalInvocationIndex] = 0u;" NL "  g_sub_output[gl_LocalInvocationIndex] = 0;" NL
347748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  groupMemoryBarrier();" NL "  barrier();" NL
347848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_add_output[gl_LocalInvocationIndex] = atomicAdd(g_add_value, 1u);" NL
347948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_sub_output[gl_LocalInvocationIndex] = atomicAdd(g_sub_value, -1);" NL "}";
348048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
348148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
348248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
348348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
348448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
348548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
348648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
348748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 16 * sizeof(int), NULL, GL_STATIC_DRAW);
348848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
348948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
349048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
349148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
349248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
349348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<int> data(8);
349448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * 8, &data[0]);
349548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::sort(data.begin(), data.end());
349648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 8; ++i)
349748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
349848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != i)
349948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3500910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3501910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
350248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
350348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
350448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
350548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
350648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(int) * 8, sizeof(int) * 8, &data[0]);
350748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::sort(data.begin(), data.end());
350848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 8; ++i)
350948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
351048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != i)
351148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3512910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3513910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
351448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
351548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
351648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
351748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
351848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
351948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
352048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
352148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
352248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
352348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
352448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
352548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
352648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
352748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
352848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
352948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicAtomicCase2 : public ComputeShaderBase
353048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
353148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
353248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
353348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Atomic functions - buffer variables";
353448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
353548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
353648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
353748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
353848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with buffer variables." NL
353948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that atomic functions work with parameters being constants and" NL
354048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    with parameters being uniforms." NL
354148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that barrier() built-in function can be used in a control flow.";
354248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
354348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
354448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
354548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
354648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
354748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify SSBO content." NL
354848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Repeat for different number of work groups and different work group sizes.";
354948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
355048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
355148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
355248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
355348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
355448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
355548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
355648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer[2];
355748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
355848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
355948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
356048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
356148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const uvec3		  global_size = local_size * num_groups;
356248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
356348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
356448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
356548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", " << global_size.y() << ", " << global_size.z()
356648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ");" NL "layout(std430, binding = 0) buffer OutputU {" NL "  uint g_uint_out["
356748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
356848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "};" NL "layout(std430, binding = 1) buffer OutputI {" NL "  int data["
356948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << global_size.x() * global_size.y() * global_size.z()
357048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "} g_int_out;" NL
357148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL
357248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  const uint global_index = gl_GlobalInvocationID.x +" NL
357348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
357448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
357548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicExchange(g_uint_out[global_index], g_uint_value[0]);" NL
357648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMin(g_uint_out[global_index], g_uint_value[1]);" NL
357748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMax(g_uint_out[global_index], g_uint_value[2]);" NL
357848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicAnd(g_uint_out[global_index], g_uint_value[3]);" NL
357948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicOr(g_uint_out[global_index], g_uint_value[4]);" NL "  if (g_uint_value[0] > 0u) {" NL
358048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    barrier();" // not needed here, just check if compiler accepts it in a control flow
358148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "    atomicXor(g_uint_out[global_index], g_uint_value[5]);" NL "  }" NL
358248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicCompSwap(g_uint_out[global_index], g_uint_value[6], g_uint_value[7]);" NL NL
358348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicExchange(g_int_out.data[global_index], 3);" NL "  atomicMin(g_int_out.data[global_index], 1);" NL
358448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMax(g_int_out.data[global_index], 2);" NL "  atomicAnd(g_int_out.data[global_index], 0x1);" NL
358548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicOr(g_int_out.data[global_index], 0x3);" NL "  atomicXor(g_int_out.data[global_index], 0x1);" NL
358648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicCompSwap(g_int_out.data[global_index], 0x2, 0x7);" NL "}";
358748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
358848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
358948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
359048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
359148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
359248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
359348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
359448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
359548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
359648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
359748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
359848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize =
359948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
360048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
360148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer[0] == 0)
360248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(2, m_storage_buffer);
360348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
360448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
360548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
360648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
360748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
360848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
360948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
361048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
361148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
361248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
361348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
361448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
361548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
361648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
361748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
361848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
361948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
362048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
362148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
362248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
362348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLuint> udata(kBufferSize);
362448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
362548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
362648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < kBufferSize; ++i)
362748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
362848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (udata[i] != 7)
362948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3630910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3631910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< udata[i] << " should be 7." << tcu::TestLog::EndMessage;
363248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
363348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
363448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
363548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
363648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLint> idata(kBufferSize);
363748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
363848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) * kBufferSize, &idata[0]);
363948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
364048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
364148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (idata[i] != 7)
364248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3643910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3644910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< idata[i] << " should be 7." << tcu::TestLog::EndMessage;
364548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
364648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
364748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
364848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
364948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
365048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
365148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
365248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
365348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program			= 0;
365448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer[0] = m_storage_buffer[1] = 0;
365548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer						  = 0;
365648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
365748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
365848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
365948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
366048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
366148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
366248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
366348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
366448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
366548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
366648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
366748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
366848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
366948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
367048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
367148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
367248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
367348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
367448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
367548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
367648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
367748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
367848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_storage_buffer);
367948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
368048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
368148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
368248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
368348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
368448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicAtomicCase3 : public ComputeShaderBase
368548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
368648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
368748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
368848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Atomic functions - shared variables";
368948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
369048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
369148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
369248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
369348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with shared variables." NL
369448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that atomic functions work with parameters being constants and" NL
369548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    with parameters being uniforms." NL
369648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that atomic functions can be used in a control flow.";
369748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
369848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
369948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
370048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
370148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
370248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify SSBO content." NL
370348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Repeat for different number of work groups and different work group sizes.";
370448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
370548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
370648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
370748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
370848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
370948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
371048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
371148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
371248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
371348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
371448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenSource(const uvec3& local_size)
371548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
371648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
371748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
371848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << local_size.z()
371948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL "  uint g_uint_out["
372048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "  int g_int_out["
372148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "};" NL "shared uint g_shared_uint["
372248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "shared int g_shared_int["
372348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << local_size.x() * local_size.y() * local_size.z()
372448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << "];" NL "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL
372548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "void main() {" NL "  atomicExchange(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[0]);" NL
372648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMin(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[1]);" NL
372748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMax(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[2]);" NL
372848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicAnd(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[3]);" NL
372948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicOr(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[4]);" NL
373048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicXor(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[5]);" NL
373148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicCompSwap(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[6], g_uint_value[7]);" NL NL
373248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicExchange(g_shared_int[gl_LocalInvocationIndex], 3);" NL
373348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMin(g_shared_int[gl_LocalInvocationIndex], 1);" NL
373448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicMax(g_shared_int[gl_LocalInvocationIndex], 2);" NL
373548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  atomicAnd(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL "  if (g_uint_value[1] > 0u) {" NL
373648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    atomicOr(g_shared_int[gl_LocalInvocationIndex], 0x3);" NL
373748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    atomicXor(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL
373848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "    atomicCompSwap(g_shared_int[gl_LocalInvocationIndex], 0x2, 0x7);" NL "  }" NL NL
373948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_uint_out[gl_LocalInvocationIndex] = g_shared_uint[gl_LocalInvocationIndex];" NL
374048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			  "  g_int_out[gl_LocalInvocationIndex] = g_shared_int[gl_LocalInvocationIndex];" NL "}";
374148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
374248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
374348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(const uvec3& local_size, bool dispatch_indirect)
374448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
374548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_program != 0)
374648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program);
374748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(GenSource(local_size));
374848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
374948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
375048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
375148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
375248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint kBufferSize = local_size.x() * local_size.y() * local_size.z();
375348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
375448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_storage_buffer == 0)
375548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
375648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
375748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize * 2, NULL, GL_DYNAMIC_DRAW);
375848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
375948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
376048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (dispatch_indirect)
376148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
376248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint num_groups[3] = { 1, 1, 1 };
376348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (m_dispatch_buffer == 0)
376448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGenBuffers(1, &m_dispatch_buffer);
376548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
376648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
376748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
376848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
376948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
377048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
377148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchCompute(1, 1, 1);
377248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
377348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
377448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
377548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLuint> udata(kBufferSize);
377648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
377748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < kBufferSize; ++i)
377848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
377948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (udata[i] != 7)
378048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3781910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3782910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< udata[i] << " should be 7." << tcu::TestLog::EndMessage;
378348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
378448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
378548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
378648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
378748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLint> idata(kBufferSize);
378848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, sizeof(GLint) * kBufferSize,
378948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						   &idata[0]);
379048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
379148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
379248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (idata[i] != 7)
379348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3794910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is "
3795910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< idata[i] << " should be 7." << tcu::TestLog::EndMessage;
379648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
379748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
379848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
379948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
380048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
380148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
380248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
380348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
380448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
380548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
380648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
380748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
380848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
380948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
381048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
381148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(64, 1, 1), false))
381248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
381348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 64), true))
381448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
381548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(1, 1, 4), false))
381648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
381748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(3, 2, 1), true))
381848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
381948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 2), false))
382048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
382148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(uvec3(2, 4, 7), true))
382248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
382348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
382448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
382548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
382648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
382748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
382848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
382948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
383048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
383148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
383248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
383348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
383448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
383548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedCopyImage : public ComputeShaderBase
383648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
383748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
383848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
383948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Copy Image";
384048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
384148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
384248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
384348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that copying two textures using CS works as expected.";
384448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
384548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
384648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
384748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Use shader image load and store operations to copy two textures in the CS.";
384848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
384948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
385048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
385148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
385248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
385348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
385448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
385548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture[2];
385648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
385748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
385848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
385948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
386048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture, 0, sizeof(m_texture));
386148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
386248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
386348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
386448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
386548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
386648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs = NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
386748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
386848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "layout(binding = 0, rgba8) uniform image2D g_input_image;" NL
386948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "layout(binding = 1, rgba8) uniform image2D g_output_image;" NL	NL
387048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "layout(local_size_x=TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
387148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "void main() {" NL "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
387248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
387348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "  const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL NL
387448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "  vec4 pixel = imageLoad(g_input_image, pixel_xy);" NL
387548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos									   "  imageStore(g_output_image, pixel_xy, pixel);" NL "}";
387648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
387748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
387848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
387948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
388048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
388148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLubyte> in_image(64 * 64 * 4, 0x0f);
388248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLubyte> out_image(64 * 64 * 4, 0x00);
388348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
388448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenTextures(2, m_texture);
388548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, m_texture[0]);
388648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
388748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &in_image[0]);
388848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
388948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
389048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
389148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &out_image[0]);
389248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
389348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
389448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
389548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
389648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(5, 4,
389748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						  1); // 5 is on purpose, to ensure that out of bounds image load and stores have no effect
389848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
389948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
390048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::vector<GLubyte> data(64 * 64 * 4);
390148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
390248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (std::size_t i = 0; i < data.size(); ++i)
390348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
390448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getWindowWidth() > 100 && data[i] != 0x0f)
390548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
3906910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
3907910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << 0x0f
3908910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "." << tcu::TestLog::EndMessage;
390948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
391048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
391148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
391248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
391348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
391448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
391548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
391648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
391748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
391848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
391948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(2, m_texture);
392048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
392148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
392248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
392348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
392448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedPipelinePreVS : public ComputeShaderBase
392548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
392648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
392748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
392848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "CS as an additional pipeline stage - Before VS (1)";
392948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
393048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
393148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
393248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that CS which runs just before VS and modifies VBO content works as expected.";
393348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
393448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
393548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
393648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Prepare VBO and VAO for a drawing operation." NL "2. Run CS to modify existing VBO content." NL
393748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Issue MemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) command." NL
393848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Issue draw call command." NL "5. Verify that the framebuffer content is as expected.";
393948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
394048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
394148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
394248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
394348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
394448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
394548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program[2];
394648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_buffer;
394748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
394848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
394948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
395048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
395148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_program, 0, sizeof(m_program));
395248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_buffer = 0;
395348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array  = 0;
395448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
395548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
395648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
395748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
395848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
395948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 4) in;" NL "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL
396048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, std430) buffer VertexBuffer {" NL "  Vertex g_vertex[];" NL "};" NL
396148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform float g_scale = 0.8;" NL "void main() {" NL
396248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_vertex[gl_GlobalInvocationID.x].position.xyz *= g_scale;" NL
396348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_vertex[gl_GlobalInvocationID.x].color *= vec4(0, 1, 0, 1);" NL "}";
396448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[0] = CreateComputeProgram(glsl_cs);
396548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[0]);
396648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[0]))
396748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
396848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
396948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
397048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
397148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "out StageData {" NL "  vec4 color;" NL "} g_vs_out;" NL "void main() {" NL
397248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  gl_Position = g_position;" NL "  g_vs_out.color = g_color;" NL "}";
397348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
397448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
397548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "in StageData {" NL "  vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
397648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  g_color = g_fs_in.color;" NL "}";
397748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[1] = CreateProgram(glsl_vs, glsl_fs);
397848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[1]);
397948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[1]))
398048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
398148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
398248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* vertex buffer */
398348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
398448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const float data[] = { -1, -1, 0, 1, 1, 1, 1, 1, 1, -1, 0, 1, 1, 1, 1, 1,
398548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								   -1, 1,  0, 1, 1, 1, 1, 1, 1, 1,  0, 1, 1, 1, 1, 1 };
398648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_vertex_buffer);
398748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
398848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
398948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ARRAY_BUFFER, 0);
399048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
399148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
399248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
399348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
399448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
399548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
399648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
399748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, 0);
399848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(0);
399948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(1);
400048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(0);
400148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
400248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_vertex_buffer);
400348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[0]);
400448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
400548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
400648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
400748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[1]);
400848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
400948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
401048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
401148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
401248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (getWindowWidth() < 500 &&
401348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			!ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
401448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
401548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
401648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
401748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
401848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
401948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
402048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
402148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
402248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 2; ++i)
402348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program[i]);
402448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_vertex_buffer);
402548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
402648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
402748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
402848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
402948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
403048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedPipelineGenDrawCommands : public ComputeShaderBase
403148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
403248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
403348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
403448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "CS as an additional pipeline stage - Before VS (2)";
403548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
403648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
403748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
403848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that a complex scenario where CS is used to generate drawing commands" NL
403948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "and write them to a draw indirect buffer works as expected. This is a practial usage of CS." NL
404048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "CS is used for culling objects which are outside of the viewing frustum.";
404148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
404248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
404348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
404448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Run CS which will generate four sets of draw call parameters and write them to the draw indirect "
404548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "buffer." NL "2. One set of draw call parameters will be: 0, 0, 0, 0" NL
404648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    (which means that an object is outside of the viewing frustum and should not be drawn)." NL
404748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Issue MemoryBarrier(GL_COMMAND_BARRIER_BIT) command." NL
404848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Issue four draw indirect commands." NL "5. Verify that the framebuffer content is as expected.";
404948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
405048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
405148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
405248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
405348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
405448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
405548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program[2];
405648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_buffer;
405748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_index_buffer;
405848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
405948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_draw_buffer;
406048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_object_buffer;
406148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
406248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
406348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
406448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_program, 0, sizeof(m_program));
406548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_buffer = 0;
406648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_index_buffer  = 0;
406748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array  = 0;
406848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_draw_buffer   = 0;
406948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_object_buffer = 0;
407048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
407148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
407248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
407348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
407448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint res;
407548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
407648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (res <= 0)
407748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
407848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
407948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return NO_ERROR;
408048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
408148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
408248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
408348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 4) in;" NL "struct DrawCommand {" NL "  uint count;" NL
408448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint instance_count;" NL "  uint first_index;" NL "  int base_vertex;" NL "  uint base_instance;" NL
408548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "};" NL "layout(std430) buffer;" NL "layout(binding = 0) readonly buffer ObjectBuffer {" NL
408648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  mat4 transform[4];" NL "  uint count[4];" NL "  uint first_index[4];" NL "} g_objects;" NL
408748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 1) writeonly buffer DrawCommandBuffer {" NL "  DrawCommand g_command[4];" NL "};" NL
408848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "bool IsObjectVisible(uint id) {" NL
408948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (g_objects.transform[id][3].x < -1.0 || g_objects.transform[id][3].x > 1.0) return false;" NL
409048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (g_objects.transform[id][3][1] < -1.0 || g_objects.transform[id][3][1] > 1.0) return false;" NL
409148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (g_objects.transform[id][3][2] < -1.0 || g_objects.transform[id][3].z > 1.0) return false;" NL
409248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  return true;" NL "}" NL "void main() {" NL "  uint id = gl_GlobalInvocationID.x;" NL
409348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_command[id].count = 0;" NL "  g_command[id].instance_count = 0;" NL
409448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_command[id].first_index = 0;" NL "  g_command[id].base_vertex = 0;" NL
409548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_command[id].base_instance = 0;" NL "  if (IsObjectVisible(id)) {" NL
409648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_command[id].count = g_objects.count[id];" NL "    g_command[id].instance_count = 1;" NL
409748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_command[id].first_index = g_objects.first_index[id];" NL "  }" NL "}";
409848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[0] = CreateComputeProgram(glsl_cs);
409948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[0]);
410048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[0]))
410148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
410248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
410348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
410448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec3 g_color;" NL
410548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "out StageData {" NL "  vec3 color;" NL "} g_vs_out;" NL
410648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, std430) buffer ObjectBuffer {" NL "  mat4 transform[4];" NL "  uint count[4];" NL
410748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint first_index[4];" NL "} g_objects;" NL "uniform int g_object_id;" NL "void main() {" NL
410848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  gl_Position = g_objects.transform[g_object_id] * g_position;" NL "  g_vs_out.color = g_color;" NL "}";
410948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
411048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
411148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "in StageData {" NL "  vec3 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
411248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  g_color = vec4(g_fs_in.color, 1);" NL "}";
411348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[1] = CreateProgram(glsl_vs, glsl_fs);
411448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[1]);
411548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[1]))
411648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
411748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, 100, 100);
411848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
411948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* object buffer */
412048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
412148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			struct
412248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
412348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				mat4   transform[4];
412448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				GLuint count[4];
412548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				GLuint first_index[4];
412648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			} data = {
412748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{ tcu::translationMatrix(vec3(-1.5f, -0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, -0.5f, 0.0f)),
412848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  tcu::translationMatrix(vec3(-0.5f, 0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, 0.5f, 0.0f)) },
412948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{ 4, 4, 4, 4 },
413048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{ 0, 4, 8, 12 }
413148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			};
413248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_object_buffer);
413348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_object_buffer);
413448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
413548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
413648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* vertex buffer */
413748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
413848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const vec3 data[] = { vec3(-0.4f, -0.4f, 0.0f), vec3(1, 0, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 0, 0),
413948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, 0.4f, 0.0f),  vec3(1, 0, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(1, 0, 0),
414048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, -0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(0, 1, 0),
414148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, 0.4f, 0.0f),  vec3(0, 1, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(0, 1, 0),
414248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, -0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, -0.4f, 0.0f), vec3(0, 0, 1),
414348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, 0.4f, 0.0f),  vec3(0, 0, 1), vec3(0.4f, 0.4f, 0.0f),  vec3(0, 0, 1),
414448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, -0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 1, 0),
414548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  vec3(-0.4f, 0.4f, 0.0f),  vec3(1, 1, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(1, 1, 0) };
414648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_vertex_buffer);
414748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
414848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
414948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ARRAY_BUFFER, 0);
415048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
415148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* index buffer */
415248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
415348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLushort data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
415448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_index_buffer);
415548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
415648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
415748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
415848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
415948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_draw_buffer);
416048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
416148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_DRAW_INDIRECT_BUFFER, 4 * sizeof(GLuint) * 5, NULL, GL_DYNAMIC_DRAW);
416248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
416348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
416448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
416548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
416648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
416748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), 0);
416848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), reinterpret_cast<void*>(sizeof(vec3)));
416948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, 0);
417048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(0);
417148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(1);
417248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
417348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(0);
417448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
417548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_draw_buffer);
417648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[0]);
417748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
417848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
417948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
418048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[1]);
418148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
418248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
418348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
418448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* draw (CPU draw calls dispatch, could be done by the GPU with ARB_multi_draw_indirect) */
418548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
418648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLsizeiptr offset = 0;
418748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 4; ++i)
418848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
418948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glUniform1i(glGetUniformLocation(m_program[1], "g_object_id"), i);
419048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glDrawElementsIndirect(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(offset));
419148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				offset += 5 * sizeof(GLuint);
419248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
419348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
419448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (getWindowWidth() >= 100 && getWindowHeight() >= 100 &&
419548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			!ValidateWindow4Quads(vec3(0), vec3(0, 1, 0), vec3(1, 1, 0), vec3(0, 0, 1)))
419648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
419748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
419848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
419948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
420048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
420148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
420248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
420348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
420448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 2; ++i)
420548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program[i]);
420648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_vertex_buffer);
420748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_index_buffer);
420848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
420948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_draw_buffer);
421048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_object_buffer);
421148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, getWindowWidth(), getWindowHeight());
421248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
421348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
421448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
421548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
421648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedPipelineComputeChain : public ComputeShaderBase
421748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
421848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
421948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
422048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Compute Chain";
422148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
422248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
422348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
422448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that dispatching several compute kernels that work in a sequence" NL
422548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    with a common set of resources works as expected." NL
422648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that indexing nested structures with built-in variables work as expected." NL
422748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that two kernels can write to the same resource without MemoryBarrier" NL
422848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    command if target regions of memory do not overlap.";
422948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
423048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
423148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
423248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create a set of GPU resources (buffers, images, atomic counters)." NL
423348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Dispatch Kernel0 that write to these resources." NL "3. Issue MemoryBarrier command." NL
423448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Dispatch Kernel1 that read/write from/to these resources." NL "5. Issue MemoryBarrier command." NL
423548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "6. Dispatch Kernel2 that read/write from/to these resources." NL
423648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "7. Verify that content of all resources is as expected.";
423748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
423848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
423948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
424048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
424148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
424248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
424348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program[3];
424448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer[4];
424548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_counter_buffer;
424648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture;
424748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_fbo;
424848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
424948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string Common()
425048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
425148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "struct S0 {" NL "  int m0[8];" NL "};" NL "struct S1 {" NL "  S0 m0[8];" NL "};" NL
425248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 0, std430) buffer Buffer0 {" NL "  int m0[5];" NL "  S1 m1[8];" NL "} g_buffer0;" NL
425348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 1, std430) buffer Buffer1 {" NL "  uint data[8];" NL "} g_buffer1;" NL
425448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 2, std430) buffer Buffer2 {" NL "  int data[256];" NL "} g_buffer2;" NL
425548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 3, std430) buffer Buffer3 {" NL "  int data[256];" NL "} g_buffer3;" NL
425648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 4, std430) buffer Buffer4 {" NL "  mat4 data0;" NL "  mat4 data1;" NL
425748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "} g_buffer4;" NL "layout(binding = 0, rgba32f) uniform image2D g_image0;" NL
425848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "layout(binding = 1, offset = 8) uniform atomic_uint g_counter[2];";
425948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
426048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	std::string GenGLSL(int p)
426148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
426248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
426348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << Common();
426448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (p == 0)
426548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
426648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL
426748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "void UpdateBuffer0(uvec3 id, int add_val) {" NL "  if (id.x < 8 && id.y < 8 && id.z < 8) {" NL
426848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    g_buffer0.m1[id.z].m0[id.y].m0[id.x] += add_val;" NL "  }" NL "}" NL
426948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "uniform int g_add_value = 1;" NL "uniform uint g_counter_y = 1;" NL
427048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "uniform vec4 g_image_value = vec4(0.125, 0.25, 0.375, 0.5);" NL "void main() {" NL
427148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  uvec3 id = gl_GlobalInvocationID;" NL "  UpdateBuffer0(id, 1);" NL
427248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  UpdateBuffer0(id, g_add_value);" NL "  if (id == uvec3(1, g_counter_y, 1)) {" NL
427348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    uint idx = atomicCounterIncrement(g_counter[1]);" NL "    g_buffer1.data[idx] = idx;" NL
427448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    idx = atomicCounterIncrement(g_counter[1]);" NL "    g_buffer1.data[idx] = idx;" NL "  }" NL
427548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  if (id.x < 4 && id.y < 4 && id.z == 0) {" NL
427648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    vec4 v = imageLoad(g_image0, ivec2(id.xy));" NL
427748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    imageStore(g_image0, ivec2(id.xy), v + g_image_value);" NL "  }" NL
427848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  if (id.x < 2 && id.y == 0 && id.z == 0) {" NL "    g_buffer2.data[id.x] -= int(g_counter_y);" NL
427948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  }" NL "}";
428048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
428148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (p == 1)
428248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
428348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 1) in;"
428448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				// translation matrix
428548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				NL "uniform mat4 g_mvp = mat4(1.0, 0.0, 0.0, 0.0,  0.0, 1.0, 0.0, 0.0,  0.0, 0.0, 1.0, 0.0,  10.0, "
428648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "20.0, 30.0, 1.0);" NL "void main() {" NL "  if (gl_GlobalInvocationID == uvec3(0)) {" NL
428748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    g_buffer4.data0 *= g_mvp;" NL "  }" NL "  if (gl_WorkGroupID == uvec3(0)) {" NL
428848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "    g_buffer4.data1[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = "
428948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "g_mvp[gl_LocalInvocationID.x][gl_LocalInvocationID.y];" NL "  }" NL "}";
429048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
429148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (p == 2)
429248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
429348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL "void main() {" NL "}";
429448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
429548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
429648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
429748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
429848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
429948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_program, 0, sizeof(m_program));
430048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
430148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_counter_buffer = 0;
430248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_texture		 = 0;
430348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
430448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
430548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
430648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
430748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		using namespace tcu;
430848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
430948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 3; ++i)
431048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
431148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			m_program[i] = CreateComputeProgram(GenGLSL(i));
431248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glLinkProgram(m_program[i]);
431348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!CheckProgram(m_program[i]))
431448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
431548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
431648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
431748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(4, m_storage_buffer);
431848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* storage buffer 0 */
431948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
432048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<int> data(5 + 8 * 8 * 8);
432148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
432248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(int)), &data[0], GL_STATIC_COPY);
432348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
432448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* storage buffer 1 */
432548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
432648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data[8] = { 0 };
432748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
432848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_COPY);
432948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
433048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* storage buffer 2 & 3 */
433148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
433248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<GLint> data(512, 7);
433348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
433448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(GLint)), &data[0], GL_STATIC_COPY);
433548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
433648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, m_storage_buffer[2], 0,
433748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							  (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
433848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer[2],
433948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							  (GLintptr)(sizeof(GLint) * data.size() / 2),
434048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							  (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
434148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
434248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* storage buffer 4 */
434348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
434448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<mat4> data(2);
434548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			data[0] = mat4(1);
434648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_storage_buffer[3]);
434748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(mat4)), &data[0], GL_STATIC_COPY);
434848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
434948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* counter buffer */
435048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
435148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint data[4] = { 0 };
435248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_counter_buffer);
435348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer);
435448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_STATIC_COPY);
435548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
435648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* texture */
435748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
435848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(4 * 4, vec4(0.0f));
435948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenTextures(1, &m_texture);
436048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_texture);
436148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
436248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
436348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0]);
436448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, 0);
436548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
436648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
436748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[0]);
436848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
436948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(2, 2, 2);
437048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
437148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(3, 2, 2);
437248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
437348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[1]);
437448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(4, 3, 7);
437548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
437648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT |
437748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
437848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
437948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate texture */
438048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
438148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(4 * 4);
438248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_texture);
438348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenFramebuffers(1, &m_fbo);
438448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
438548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
438648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<GLubyte> colorData(4 * 4 * 4);
438748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
438848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 4 * 4 * 4; i += 4)
438948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
439048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[i / 4] =
439148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
439248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
439348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
439448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (std::size_t i = 0; i < data.size(); ++i)
439548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
439648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!ColorEqual(data[i], vec4(0.25f, 0.5f, 0.75f, 1.0f), g_color_eps))
439748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4398910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
4399910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Invalid data at texture." << tcu::TestLog::EndMessage;
440048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
440148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
440248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
440348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
440448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate storage buffer 0 */
440548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
440648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<int> data(5 + 8 * 8 * 8);
440748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
440848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(data.size() * sizeof(int)), &data[0]);
440948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (std::size_t i = 5; i < data.size(); ++i)
441048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
441148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (data[i] != 4)
441248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4413910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4414910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski														<< " should be 2." << tcu::TestLog::EndMessage;
441548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
441648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
441748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
441848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
441948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate storage buffer 1 */
442048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
442148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint data[8];
442248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
442348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
442448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint i = 0; i < 4; ++i)
442548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
442648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (data[i] != i)
442748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4428910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4429910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski														<< " should be " << i << "." << tcu::TestLog::EndMessage;
443048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
443148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
443248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
443348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
443448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate storage buffer 2 & 3 */
443548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
443648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<GLint> data(512);
443748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
443848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(GLint) * data.size()), &data[0]);
443948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 2; ++i)
444048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
444148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (data[i] != 5)
444248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4443910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4444910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski														<< " should be: 5." << tcu::TestLog::EndMessage;
444548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
444648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
444748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (data[i + 256] != 7)
444848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4449910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i + 256]
4450910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski														<< " should be: 7." << tcu::TestLog::EndMessage;
445148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
445248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
445348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
445448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
445548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate storage buffer 4 */
445648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
445748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			mat4 data[2];
445848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[3]);
445948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0](0, 0));
4460fe6a4d09be7c3502c95107cddd05cb41e193c38dNicolai Hähnle			if (data[0] != translationMatrix(vec3(10.0f, 20.0f, 30.0f)))
446148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
4462910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
4463910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
446448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
446548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
4466fe6a4d09be7c3502c95107cddd05cb41e193c38dNicolai Hähnle			if (data[1] != transpose(translationMatrix(vec3(10.0f, 20.0f, 30.0f))))
446748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
4468910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
4469910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
447048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
447148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
447248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
447348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate counter buffer */
447448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
447548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint data[4] = { 0 };
447648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(data), data);
447748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[3] != 4)
447848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
4479910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
4480910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is: " << data[3] << " should be: 4." << tcu::TestLog::EndMessage;
448148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
448248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
448348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
448448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
448548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
448648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
448748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
448848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
448948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
449048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 3; ++i)
449148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program[i]);
449248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(4, m_storage_buffer);
449348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_counter_buffer);
449448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(1, &m_texture);
449548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteFramebuffers(1, &m_fbo);
449648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
449748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
449848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
449948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
450048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedPipelinePostFS : public ComputeShaderBase
450148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
450248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
450348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
450448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "CS as an additional pipeline stage - After FS";
450548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
450648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
450748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
450848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that CS which runs just after FS to do a post-processing on a rendered image works as "
450948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "expected." NL "2. Verify that CS used as a post-processing filter works as expected." NL
451048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that several CS kernels which run in a sequence to do a post-processing on a rendered "
451148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "image works as expected.";
451248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
451348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
451448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
451548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
451648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"1. Render image to Texture0 using VS and FS." NL
451748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"2. Use Texture0 as an input to Kernel0 which performs post-processing and writes result to Texture1." NL
451848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"3. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
451948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"4. Use Texture1 as an input to Kernel1 which performs post-processing and writes result to Texture0." NL
452048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"5. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
452148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"6. Verify content of the final post-processed image (Texture0).";
452248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
452348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
452448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
452548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
452648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
452748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
452848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program[3];
452948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_render_target[2];
453048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_framebuffer;
453148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
453248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
453348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
453448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
453548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_program, 0, sizeof(m_program));
453648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_render_target, 0, sizeof(m_render_target));
453748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_framebuffer  = 0;
453848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array = 0;
453948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
454048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
454148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
454248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
454348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
454448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
454548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "const vec2 g_vertex[4] = vec2[4](vec2(0), vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
454648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  gl_Position = vec4(g_vertex[gl_VertexID], 0, 1);" NL "}";
454748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
454848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
454948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1, 0, 0, 1);" NL "}";
455048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
455148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[0] = CreateProgram(glsl_vs, glsl_fs);
455248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[0]);
455348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[0]))
455448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
455548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
455648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
455748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
455848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
455948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
456048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL	NL
456148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "void main() {" NL
456248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
456348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL NL "  if (thread_xy == ivec2(0)) {" NL
456448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    const ivec2 pixel_xy = tile_xy * kTileSize;" NL "    for (int y = 0; y < TILE_HEIGHT; ++y) {" NL
456548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "      for (int x = 0; x < TILE_WIDTH; ++x) {" NL
456648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "        imageStore(g_output_image, pixel_xy + ivec2(x, y), vec4(0, 1, 0, 1));" NL "      }" NL
456748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    }" NL "  }" NL "}";
456848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
456948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[1] = CreateComputeProgram(glsl_cs);
457048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[1]);
457148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[1]))
457248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
457348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
457448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs2 = NL "#define TILE_WIDTH 32" NL "#define TILE_HEIGHT 32" NL
457548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
457648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
457748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL	NL
457848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
457948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"vec4 Process(vec4 ic) {" NL "  return ic + vec4(1, 0, 0, 0);" NL "}" NL
458048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"void main() {" NL "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
458148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
458248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"  const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL
458348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"  vec4 ic = imageLoad(g_input_image, pixel_xy);" NL
458448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										"  imageStore(g_output_image, pixel_xy, Process(ic));" NL "}";
458548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[2] = CreateComputeProgram(glsl_cs2);
458648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[2]);
458748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[2]))
458848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
458948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
459048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
459148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
459248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init render targets */
459348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
459448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(128 * 128);
459548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenTextures(2, m_render_target);
459648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 2; ++i)
459748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
459848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glBindTexture(GL_TEXTURE_2D, m_render_target[i]);
459948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
460048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 128, 128, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
460148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
460248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, 0);
460348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
460448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
460548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenFramebuffers(1, &m_framebuffer);
460648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
460748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_render_target[0], 0);
460848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindFramebuffer(GL_FRAMEBUFFER, 0);
460948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
461048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
461148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[0]);
461248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
461348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
461448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, 128, 128);
461548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// draw full-viewport triangle
461648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLES, 1,
461748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 3); // note: <first> is 1 this means that gl_VertexID in the VS will be: 1, 2 and 3
461848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindFramebuffer(GL_FRAMEBUFFER, 0);
461948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
462048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_render_target[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);  // input
462148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(1, m_render_target[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
462248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[1]);
462348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(128 / 16, 128 / 16, 1);
462448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
462548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(0, m_render_target[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);  // input
462648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(1, m_render_target[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
462748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[2]);
462848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
462948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(128 / 32, 128 / 32, 1);
463048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
463148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate render target */
463248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
463348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(128 * 128);
463448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_render_target[0]);
463548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
463648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
463748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (std::size_t i = 0; i < data.size(); ++i)
463848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
463948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!IsEqual(data[i], vec4(1, 1, 0, 1)))
464048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4641910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
4642910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
464348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
464448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
464548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
464648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
464748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
464848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
464948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
465048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
465148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
465248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glViewport(0, 0, getWindowWidth(), getWindowHeight());
465348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
465448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 3; ++i)
465548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program[i]);
465648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(2, m_render_target);
465748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
465848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteFramebuffers(1, &m_framebuffer);
465948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
466048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
466148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
466248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
466348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedPipelinePostXFB : public ComputeShaderBase
466448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
466548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
466648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
466748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "CS as an additional pipeline stage - After XFB";
466848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
466948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
467048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
467148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that CS which process data fedback by VS works as expected." NL
467248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that XFB and SSBO works correctly together in one shader." NL
467348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that 'switch' statment which selects different execution path for each CS thread works as "
467448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "expected.";
467548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
467648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
467748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
467848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Draw triangle with XFB enabled. Some data is written to the XFB buffer." NL
467948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Use XFB buffer as 'input SSBO' in CS. Process data and write it to 'output SSBO'." NL
468048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify 'output SSBO' content.";
468148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
468248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
468348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
468448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
468548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
468648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
468748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program[2];
468848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
468948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_xfb_buffer;
469048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_buffer;
469148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
469248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
469348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
469448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
469548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_program, 0, sizeof(m_program));
469648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
469748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_xfb_buffer	 = 0;
469848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_buffer  = 0;
469948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array   = 0;
470048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
470148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
470248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
470348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
470448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint res;
470548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
470648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (res <= 0)
470748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
470848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
470948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return NO_ERROR;
471048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
471148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
471248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
471348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
471448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL "out StageData {" NL
471548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vec4 color;" NL "} g_vs_out;" NL "layout(binding = 0, std430) buffer StageData {" NL
471648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  Vertex vertex[];" NL "} g_vs_buffer;" NL "void main() {" NL "  gl_Position = g_position;" NL
471748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_vs_out.color = g_color;" NL "  g_vs_buffer.vertex[gl_VertexID].position = g_position;" NL
471848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_vs_buffer.vertex[gl_VertexID].color = g_color;" NL "}";
471948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
472048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
472148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "in StageData {" NL "  vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
472248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  g_color = g_fs_in.color;" NL "}";
472348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
472448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[0] = CreateProgram(glsl_vs, glsl_fs);
472548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* setup xfb varyings */
472648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
472748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const var[2] = { "gl_Position", "StageData.color" };
472848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTransformFeedbackVaryings(m_program[0], 2, var, GL_INTERLEAVED_ATTRIBS);
472948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
473048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[0]);
473148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[0]))
473248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
473348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
473448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
473548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 3) in;" NL "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL
473648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 3, std430) buffer Buffer {" NL "  Vertex g_vertex[3];" NL "};" NL
473748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform vec4 g_color1 = vec4(0, 0, 1, 0);" NL "uniform int g_two = 2;" NL
473848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void UpdateVertex2(int i) {" NL "  g_vertex[i].color -= vec4(-1, 1, 0, 0);" NL "}" NL "void main() {" NL
473948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  switch (gl_GlobalInvocationID.x) {" NL
474048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 0: g_vertex[gl_GlobalInvocationID.x].color += vec4(1, 0, 0, 0); break;" NL
474148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 1: g_vertex[1].color += g_color1; break;" NL "    case 2: UpdateVertex2(g_two); break;" NL
474248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    default: return;" NL "  }" NL "}";
474348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program[1] = CreateComputeProgram(glsl_cs);
474448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program[1]);
474548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program[1]))
474648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
474748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
474848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
474948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
475048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STATIC_COPY);
475148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
475248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_xfb_buffer);
475348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfb_buffer);
475448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STREAM_COPY);
475548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
475648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const float in_data[3 * 8] = { -1, -1, 0, 1, 0, 1, 0, 1, 3, -1, 0, 1, 0, 1, 0, 1, -1, 3, 0, 1, 0, 1, 0, 1 };
475748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_vertex_buffer);
475848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
475948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_ARRAY_BUFFER, sizeof(in_data), in_data, GL_STATIC_DRAW);
476048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, 0);
476148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
476248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
476348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
476448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
476548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
476648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
476748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_ARRAY_BUFFER, 0);
476848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(0);
476948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnableVertexAttribArray(1);
477048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(0);
477148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
477248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT);
477348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[0]);
477448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
477548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBeginTransformFeedback(GL_TRIANGLES);
477648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLES, 0, 3);
477748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEndTransformFeedback();
477848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
477948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_xfb_buffer);
478048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program[1]);
478148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
478248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
478348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
478448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
478548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate storage buffer */
478648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
478748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			float data[3 * 8];
478848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
478948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
479048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (memcmp(data, in_data, sizeof(data)) != 0)
479148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
4792910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
4793910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data in shader storage buffer is incorrect."
4794910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::EndMessage;
479548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
479648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
479748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
479848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate xfb buffer */
479948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
480048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const float ref_data[3 * 8] = {
480148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				-1, -1, 0, 1, 1, 1, 0, 1, 3, -1, 0, 1, 0, 1, 1, 1, -1, 3, 0, 1, 1, 0, 0, 1
480248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			};
480348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
480448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			float data[3 * 8];
480548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data);
480648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (memcmp(data, ref_data, sizeof(data)) != 0)
480748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
4808910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
4809910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data in xfb buffer is incorrect." << tcu::TestLog::EndMessage;
481048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
481148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
481248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
481348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
481448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
481548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
481648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
481748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
481848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
481948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
482048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
482148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
482248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
482348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int i = 0; i < 2; ++i)
482448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteProgram(m_program[i]);
482548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_vertex_buffer);
482648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
482748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_xfb_buffer);
482848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
482948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
483048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
483148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
483248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
483348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedSharedIndexing : public ComputeShaderBase
483448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
483548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
483648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
483748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Shared Memory - Indexing";
483848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
483948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
484048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
484148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that indexing various types of shared memory works as expected." NL
484248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that indexing shared memory with different types of expressions work as expected." NL
484348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that all declaration types of shared structures are supported by the GLSL compiler.";
484448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
484548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
484648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
484748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses shared memory in many different ways." NL
484848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Write to shared memory using different expressions." NL "3. Validate shared memory content." NL
484948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Use synchronization primitives (barrier, groupMemoryBarrier) where applicable.";
485048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
485148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
485248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
485348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everyting works as expected.";
485448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
485548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
485648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
485748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture;
485848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
485948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
486048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
486148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
486248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_texture = 0;
486348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
486448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
486548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
486648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
486748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs = NL
486848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout(binding = 3, rgba32f) uniform image2D g_result_image;" NL
486948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout (local_size_x = 4,local_size_y=4 ) in;" NL "shared vec4 g_shared1[4];" NL
487048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"shared mat4 g_shared2;" NL "shared struct {" NL "  float data[4];" NL "} g_shared3[4];" NL
487148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"shared struct Type { float data[4]; } g_shared4[4];" NL "shared Type g_shared5[4];" NL
487248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform bool g_true = true;" NL
487348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform float g_values[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };" NL NL
487448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void Sync() {" NL "  groupMemoryBarrier();" NL "  barrier();" NL "}" NL
487548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void SetMemory(ivec2 xy, float value) {" NL "  g_shared1[xy.y][gl_LocalInvocationID.x] = value;" NL
487648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  g_shared2[xy.y][xy.x] = value;" NL "  g_shared3[xy[1]].data[xy[0]] = value;" NL
487748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  g_shared4[xy.y].data[xy[0]] = value;" NL
487848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  g_shared5[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] = value;" NL "}" NL
487948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"bool CheckMemory(ivec2 xy, float expected) {" NL
488048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_shared1[xy.y][xy[0]] != expected) return false;" NL
488148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_shared2[xy[1]][xy[0]] != expected) return false;" NL
488248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_shared3[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] != expected) return false;" NL
488348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_shared4[gl_LocalInvocationID.y].data[xy.x] != expected) return false;" NL
488448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_shared5[xy.y].data[xy.x] != expected) return false;" NL "  return true;" NL "}" NL
488548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void main() {" NL "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
488648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  vec4 result = vec4(0, 1, 0, 1);" NL NL
488748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0);" NL "  Sync();" NL
488848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0)) result = vec4(1, 0, 0, 1);" NL NL
488948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0);" NL "  Sync();" NL
489048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0)) result = vec4(1, 0, 0, 1);" NL NL
489148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_true && gl_LocalInvocationID.x < 10) {" NL
489248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0);" NL "    Sync();" NL
489348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"    if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0)) result = vec4(1, 0, 0, 1);" NL
489448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  }" NL NL "  imageStore(g_result_image, thread_xy, result);" NL "}";
489548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
489648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
489748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
489848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
489948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
490048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init texture */
490148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
490248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(4 * 4);
490348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenTextures(1, &m_texture);
490448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_texture);
490548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
490648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
490748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, 0);
490848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
490948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
491048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindImageTexture(3, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
491148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
491248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
491348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
491448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate render target */
491548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
491648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(4 * 4);
491748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_2D, m_texture);
491848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
491948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
492048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (std::size_t i = 0; i < data.size(); ++i)
492148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
492248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!IsEqual(data[i], vec4(0, 1, 0, 1)))
492348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
4924910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
4925910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
492648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
492748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
492848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
492948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
493048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
493148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
493248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
493348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
493448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
493548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
493648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(1, &m_texture);
493748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
493848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
493948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
494048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
494148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedSharedMax : public ComputeShaderBase
494248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
494348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
494448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
494548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Shared Memory - 32K";
494648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
494748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
494848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
494948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Support for 32K of shared memory is required by the OpenGL specifaction. Verify if an "
495048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "implementation supports it.";
495148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
495248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
495348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
495448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Create and dispatch CS which uses 32K of shared memory.";
495548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
495648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
495748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
495848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
495948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
496048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
496148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
496248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_buffer;
496348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
496448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
496548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
496648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
496748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_buffer  = 0;
496848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
496948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
497048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
497148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
497248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
497348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1024) in;" NL
497448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "shared struct Type { vec4 v[2]; } g_shared[1024];" // 32768 bytes of shared memory
497548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(std430) buffer Output {" NL "  Type g_output[1024];" NL "};" NL NL "void main() {" NL
497648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const int id = int(gl_GlobalInvocationID.x);" NL
497748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shared[id].v = vec4[2](vec4(1.0), vec4(1.0));" NL "  memoryBarrierShared();" NL "  barrier();" NL NL
497848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vec4 sum = vec4(0.0);" NL "  int sum_count = 0;" NL "  for (int i = id - 3; i < id + 4; ++i) {" NL
497948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    if (id >= 0 && id < g_shared.length()) {" NL "      sum += g_shared[id].v[0];" NL
498048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "      sum += g_shared[id].v[1];" NL "      sum_count += 2;" NL "    }" NL "  }" NL
498148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (any(greaterThan(abs((sum / sum_count) - vec4(1.0)), vec4(0.0000001f)))) return;" NL NL
498248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[id] = g_shared[id];" NL "}";
498348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
498448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
498548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
498648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
498748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
498848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init buffer */
498948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
499048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(1024 * 2);
499148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_buffer);
499248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
499348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
499448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						 GL_DYNAMIC_COPY);
499548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
499648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
499748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
499848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
499948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
500048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
500148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate buffer */
500248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
500348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(1024 * 2);
500448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0]);
500548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (std::size_t i = 0; i < data.size(); ++i)
500648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
500748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!IsEqual(data[i], vec4(1.0f)))
500848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
5009910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
5010910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
501148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
501248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
501348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
501448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
501548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
501648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
501748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
501848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
501948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
502048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
502148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_buffer);
502248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
502348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
502448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
502548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
502648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedDynamicPaths : public ComputeShaderBase
502748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
502848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
502948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
503048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Dynamic execution paths";
503148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
503248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
503348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
503448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify case where each of the four threads takes different execution path in the CS." NL
503548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Execution path for each thread is not known at the compilation time." NL
503648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    Selection is made based on the result of the texture sampling." NL
503748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that memory synchronization primitives (memoryBarrier* functions) are accepted" NL
503848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    in the control flow.";
503948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
504048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
504148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
504248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create and dispatch CS that takes different execution paths based on the result of the texture "
504348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "sampling." NL "2. In each execution path use different resources (buffers, samplers, uniform "
504448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "arrays) to compute output value.";
504548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
504648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
504748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
504848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
504948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
505048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
505148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
505248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_buffer[4];
505348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture[2];
505448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
505548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
505648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
505748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
505848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_buffer, 0, sizeof(m_buffer));
505948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture, 0, sizeof(m_texture));
506048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
506148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
506248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
506348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
506448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
506548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer Output {" NL
506648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vec4 g_output[4];" NL "};" NL "uniform isamplerBuffer g_path_buffer;" NL
506748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform vec4[4] g_input0 = vec4[4](vec4(100), vec4(200), vec4(300), vec4(400));" NL
506848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform samplerBuffer g_input1;" NL "layout(binding = 1, std430) buffer Input2 {" NL
506948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  vec4[4] g_input2;" NL "};" NL NL "void Path2(int id) {" NL
507048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[id] = texelFetch(g_input1, int(gl_LocalInvocationIndex));" NL "}" NL "void main() {" NL
507148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const int id = int(gl_GlobalInvocationID.x);" NL
507248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  const int path = texelFetch(g_path_buffer, id).x;" NL NL "  if (path == 0) {" NL
507348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_output[id] = g_input0[gl_LocalInvocationID.x];" NL "    memoryBarrier();" NL
507448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  } else if (path == 1) {" NL "    return;" NL "  } else if (path == 2) {" NL "    Path2(id);" NL
507548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    return;" NL "  } else if (path == 3) {" NL "    g_output[id] = g_input2[path - 1];" NL
507648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    memoryBarrierBuffer();" NL "  }" NL "}";
507748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
507848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
507948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
508048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
508148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
508248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(4, m_buffer);
508348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenTextures(2, m_texture);
508448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
508548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init 'output' buffer */
508648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
508748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<vec4> data(4, vec4(-100.0f));
508848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
508948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
509048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						 GL_DYNAMIC_COPY);
509148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
509248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init 'input2' buffer */
509348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
509448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const vec4 data[4] = { vec4(1.0f), vec4(2.0f), vec4(3.0f), vec4(4.0f) };
509548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
509648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data[0][0], GL_DYNAMIC_COPY);
509748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
509848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init 'path' buffer */
509948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
510048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data[4] = { 3, 2, 1, 0 };
510148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[2]);
510248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
510348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, 0);
510448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
510548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, m_buffer[2]);
510648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, 0);
510748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
510848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* init 'input1' buffer */
510948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
511048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const vec4 data[4] = { vec4(10.0f), vec4(20.0f), vec4(30.0f), vec4(40.0f) };
511148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[3]);
511248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
511348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, 0);
511448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
511548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_buffer[3]);
511648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, 0);
511748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
511848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
511948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
512048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "g_path_buffer"), 0);
512148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "g_input1"), 1);
512248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE0);
512348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
512448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glActiveTexture(GL_TEXTURE1);
512548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
512648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
512748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
512848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
512948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate 'output' buffer */
513048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
513148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			vec4 data[4];
513248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[0]);
513348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0][0]);
513448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
513548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const vec4 expected[4] = { vec4(3.0f), vec4(20.0f), vec4(-100.0f), vec4(400.0f) };
513648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 4; ++i)
513748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
513848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (!IsEqual(data[i], expected[i]))
513948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
5140910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
5141910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
514248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
514348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
514448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
514548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
514648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
514748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
514848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
514948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
515048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
515148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
515248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(4, m_buffer);
515348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(2, m_texture);
515448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
515548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
515648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
515748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
515848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedResourcesMax : public ComputeShaderBase
515948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
516048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
516148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
516248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Maximum number of resources in one shader";
516348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
516448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
516548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
516648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that using 8 SSBOs, 12 UBOs, 8 atomic counters, 16 samplers" NL
516748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    and 8 images in one CS works as expected.";
516848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
516948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
517048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
517148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Create and dispatch CS. Verify result.";
517248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
517348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
517448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
517548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
517648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
517748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
517848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
517948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer[8];
518048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_uniform_buffer[12];
518148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_atomic_buffer[8];
518248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture_buffer[16];
518348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_texture[16];
518448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_image_buffer[8];
518548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_image[8];
518648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
518748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool RunIteration(GLuint index)
518848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
518948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 8; ++i)
519048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
519148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data = i + 1;
519248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
519348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
519448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
519548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 12; ++i)
519648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
519748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data = i + 1;
519848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
519948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
520048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
520148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 8; ++i)
520248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
520348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data = i + 1;
520448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, m_atomic_buffer[i]);
520548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
520648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
520748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 16; ++i)
520848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
520948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data = i + 1;
521048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer[i]);
521148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_READ);
521248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, 0);
521348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
521448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glActiveTexture(GL_TEXTURE0 + i);
521548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, m_texture[i]);
521648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_texture_buffer[i]);
521748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
521848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 8; ++i)
521948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
522048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data = i + 1;
522148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, m_image_buffer[i]);
522248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
522348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_TEXTURE_BUFFER, 0);
522448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
522548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, m_image[i]);
522648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_image_buffer[i]);
522748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindTexture(GL_TEXTURE_BUFFER, 0);
522848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
522948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindImageTexture(i, m_image[i], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
523048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
523148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
523248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
523348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1ui(glGetUniformLocation(m_program, "g_index"), index);
523448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* uniform array */
523548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
523648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			std::vector<GLuint> data(480);
523748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (GLuint i = 0; i < static_cast<GLuint>(data.size()); ++i)
523848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				data[i]   = i + 1;
523948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniform1uiv(glGetUniformLocation(m_program, "g_uniform_def"), static_cast<GLsizei>(data.size()),
524048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						  &data[0]);
524148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
524248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
524348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
524448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
524548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		bool result = true;
524648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate buffer */
524748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
524848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint data;
524948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[index]);
525048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
525148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
525248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != (index + 1) * 6)
525348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5254910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data << " should be "
5255910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski													<< (index + 1) * 6 << "." << tcu::TestLog::EndMessage;
525648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				result = false;
525748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
525848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
525948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
526048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return result;
526148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
526248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
526348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
526448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
526548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
526648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
526748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_atomic_buffer, 0, sizeof(m_atomic_buffer));
526848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
526948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_texture, 0, sizeof(m_texture));
527048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_image_buffer, 0, sizeof(m_image_buffer));
527148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_image, 0, sizeof(m_image));
527248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
527348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
527448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
527548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
527648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
527748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
527848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint data;" NL "} g_shader_storage[8];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
527948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint data;" NL "} g_uniform[12];" NL "layout(binding = 0) uniform usamplerBuffer g_sampler[16];" NL
528048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, r32ui) uniform uimageBuffer g_image[8];" NL
528148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter0;" NL
528248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 1, offset = 0) uniform atomic_uint g_atomic_counter1;" NL
528348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 2, offset = 0) uniform atomic_uint g_atomic_counter2;" NL
528448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 3, offset = 0) uniform atomic_uint g_atomic_counter3;" NL
528548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 4, offset = 0) uniform atomic_uint g_atomic_counter4;" NL
528648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 5, offset = 0) uniform atomic_uint g_atomic_counter5;" NL
528748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 6, offset = 0) uniform atomic_uint g_atomic_counter6;" NL
528848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(binding = 7, offset = 0) uniform atomic_uint g_atomic_counter7;" NL
528948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform uint g_uniform_def[480];" NL "uniform uint g_index = 0u;" NL NL "uint Add() {" NL
529048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  switch (g_index) {" NL "    case 0: return atomicCounter(g_atomic_counter0);" NL
529148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 1: return atomicCounter(g_atomic_counter1);" NL
529248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 2: return atomicCounter(g_atomic_counter2);" NL
529348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 3: return atomicCounter(g_atomic_counter3);" NL
529448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 4: return atomicCounter(g_atomic_counter4);" NL
529548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 5: return atomicCounter(g_atomic_counter5);" NL
529648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 6: return atomicCounter(g_atomic_counter6);" NL
529748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    case 7: return atomicCounter(g_atomic_counter7);" NL "  }" NL "}" NL "void main() {" NL
529848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shader_storage[g_index].data += g_uniform[g_index].data;" NL
529948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shader_storage[g_index].data += texelFetch(g_sampler[g_index], 0).x;" NL
530048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shader_storage[g_index].data += imageLoad(g_image[g_index], 0).x;" NL
530148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shader_storage[g_index].data += Add();" NL
530248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shader_storage[g_index].data += g_uniform_def[g_index];" NL "}";
530348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
530448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
530548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
530648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
530748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
530848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(16, m_storage_buffer);
530948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(12, m_uniform_buffer);
531048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(8, m_atomic_buffer);
531148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(16, m_texture_buffer);
531248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenTextures(16, m_texture);
531348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(8, m_image_buffer);
531448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenTextures(8, m_image);
531548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
531648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(0))
531748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
531848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(1))
531948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
532048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!RunIteration(5))
532148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
532248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
532348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
532448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
532548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
532648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
532748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
532848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
532948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(16, m_storage_buffer);
533048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(12, m_uniform_buffer);
533148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(8, m_atomic_buffer);
533248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(16, m_texture_buffer);
533348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(16, m_texture);
533448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(8, m_image_buffer);
533548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteTextures(8, m_image);
533648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
533748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
533848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
533948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
534048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedFP64Case1 : public ComputeShaderBase
534148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
534248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
534348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
534448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "FP64 support - built-in math functions";
534548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
534648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
534748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
534848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that selected double precision math functions works as expected in the CS.";
534948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
535048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
535148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
535248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Create and dispatch CS which uses double precision math functions. Verify results.";
535348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
535448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
535548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
535648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
535748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
535848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
535948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
536048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer[4];
536148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_uniform_buffer[2];
536248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
536348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
536448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
536548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
536648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
536748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
536848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
536948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
537048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
537148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
537248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
537348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
537448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  double data;" NL "} g_shader_storage[4];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
537548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  double data;" NL "} g_uniform[2];" NL "uniform dvec2 g_uniform_def;" NL NL "void main() {" NL
537648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  if (gl_GlobalInvocationID.x == 0) {" NL
537748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_shader_storage[0].data = floor(g_uniform[0].data + 0.1LF);" // floor(1.1LF) == 1.0LF
537848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  } else if (gl_GlobalInvocationID.x == 1) {" NL
537948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_shader_storage[1].data = ceil(g_uniform[1].data + 0.2LF);" // ceil(2.2LF) == 3.0LF
538048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  } else if (gl_GlobalInvocationID.x == 2) {" NL
538148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_shader_storage[2].data = min(g_uniform_def[0] + 0.1LF, 1.0LF);" // min(1.1LF, 1.0LF) == 1.0LF
538248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  } else if (gl_GlobalInvocationID.x == 3) {" NL
538348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    g_shader_storage[3].data = max(g_uniform_def[0], g_uniform_def.y);" // max(1.0LF, 2.0LF) == 2.0LF
538448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "  }" NL "}";
538548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
538648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
538748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
538848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
538948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
539048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(4, m_storage_buffer);
539148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 4; ++i)
539248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
539348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble data = static_cast<GLdouble>(i + 1);
539448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
539548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
539648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
539748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
539848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(2, m_uniform_buffer);
539948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 2; ++i)
540048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
540148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble data = static_cast<GLdouble>(i + 1);
540248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
540348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
540448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
540548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
540648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
540748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform2d(glGetUniformLocation(m_program, "g_uniform_def"), 1.0, 2.0);
540848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
540948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
541048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
541148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
541248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
541348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble expected[4] = { 1.0, 3.0, 1.0, 2.0 };
541448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 4; ++i)
541548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
541648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				GLdouble data;
541748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[i]);
541848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
541948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (data != expected[i])
542048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
5421910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
5422910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Data at index " << i << " is " << data << " should be "
5423910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< expected[i] << "." << tcu::TestLog::EndMessage;
542448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
542548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
542648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
542748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
542848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
542948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
543048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
543148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
543248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
543348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
543448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(4, m_storage_buffer);
543548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(2, m_uniform_buffer);
543648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
543748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
543848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
543948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
544048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedFP64Case2 : public ComputeShaderBase
544148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
544248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
544348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
544448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "FP64 support - uniform variables";
544548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
544648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
544748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
544848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Verify that all types of double precision uniform variables work as expected in CS." NL
544948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Verify that all double precision uniform variables can be updated with Uniform* and "
545048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "ProgramUniform* commands." NL "3. Verify that re-linking CS program works as expected.";
545148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
545248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
545348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
545448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Create CS which uses all (double precision) types of uniform variables." NL
545548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Update uniform variables with ProgramUniform* commands." NL
545648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
545748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "5. Update uniform variables with Uniform* commands." NL
545848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "6. Verify that uniform variables were updated correctly.";
545948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
546048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
546148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
546248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
546348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
546448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
546548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
546648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
546748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
546848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
546948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
547048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
547148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
547248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
547348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
547448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
547548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
547648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs = NL
547748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"layout(local_size_x = 1) in;" NL "buffer Result {" NL "  int g_result;" NL "};" NL "uniform double g_0;" NL
547848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform dvec2 g_1;" NL "uniform dvec3 g_2;" NL "uniform dvec4 g_3;" NL "uniform dmat2 g_4;" NL
547948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform dmat2x3 g_5;" NL "uniform dmat2x4 g_6;" NL "uniform dmat3x2 g_7;" NL "uniform dmat3 g_8;" NL
548048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform dmat3x4 g_9;" NL "uniform dmat4x2 g_10;" NL "uniform dmat4x3 g_11;" NL "uniform dmat4 g_12;" NL NL
548148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void main() {" NL "  g_result = 1;" NL NL "  if (g_0 != 1.0LF) g_result = 0;" NL
548248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_1 != dvec2(2.0LF, 3.0LF)) g_result = 0;" NL
548348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_2 != dvec3(4.0LF, 5.0LF, 6.0LF)) g_result = 0;" NL
548448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_3 != dvec4(7.0LF, 8.0LF, 9.0LF, 10.0LF)) g_result = 0;" NL NL
548548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_4 != dmat2(11.0LF, 12.0LF, 13.0LF, 14.0LF)) g_result = 0;" NL
548648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_5 != dmat2x3(15.0LF, 16.0LF, 17.0LF, 18.0LF, 19.0LF, 20.0LF)) g_result = 0;" NL
548748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_6 != dmat2x4(21.0LF, 22.0LF, 23.0LF, 24.0LF, 25.0LF, 26.0LF, 27.0LF, 28.0LF)) g_result = 0;" NL NL
548848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_7 != dmat3x2(29.0LF, 30.0LF, 31.0LF, 32.0LF, 33.0LF, 34.0LF)) g_result = 0;" NL
548948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_8 != dmat3(35.0LF, 36.0LF, 37.0LF, 38.0LF, 39.0LF, 40.0LF, 41.0LF, 42.0LF, 43.0LF)) g_result = "
549048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"0;" NL "  if (g_9 != dmat3x4(44.0LF, 45.0LF, 46.0LF, 47.0LF, 48.0LF, 49.0LF, 50.0LF, 51.0LF, 52.0LF, "
549148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"53.0LF, 54.0LF, 55.0LF)) g_result = 0;" NL NL
549248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_10 != dmat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
549348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  if (g_11 != dmat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
549448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"0;" NL "  if (g_12 != dmat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
549548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"88.0, 89.0, 90.0)) g_result = 0;" NL "}";
549648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
549748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
549848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
549948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
550048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
550148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
550248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create buffer */
550348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
550448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data = 123;
550548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
550648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
550748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
550848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
550948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform1d(m_program, glGetUniformLocation(m_program, "g_0"), 1.0);
551048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform2d(m_program, glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
551148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform3d(m_program, glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
551248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glProgramUniform4d(m_program, glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
551348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
551448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2 */
551548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
551648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
551748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2dv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
551848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
551948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x3 */
552048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
552148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
552248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2x3dv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
552348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
552448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x4 */
552548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
552648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
552748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix2x4dv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
552848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
552948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
553048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x2 */
553148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
553248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
553348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3x2dv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
553448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
553548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3 */
553648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
553748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
553848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3dv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
553948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
554048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x4 */
554148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
554248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
554348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix3x4dv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
554448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
554548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
554648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x2 */
554748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
554848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
554948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4x2dv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
555048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
555148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x3 */
555248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
555348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
555448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4x3dv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
555548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
555648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4 */
555748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
555848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
555948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
556048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glProgramUniformMatrix4dv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
556148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
556248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
556348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
556448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
556548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
556648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
556748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
556848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
556948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
557048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
557148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
557248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5573910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
5574910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
557548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
557648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
557748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
557848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
557948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// re-link program (all uniforms will be set to zero)
558048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
558148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
558248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* clear buffer */
558348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
558448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data = 123;
558548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
558648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
558748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
558848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1d(glGetUniformLocation(m_program, "g_0"), 1.0);
558948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform2d(glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
559048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform3d(glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
559148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform4d(glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
559248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
559348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2 */
559448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
559548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
559648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2dv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
559748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
559848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x3 */
559948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
560048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
560148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2x3dv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
560248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
560348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat2x4 */
560448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
560548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
560648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix2x4dv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
560748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
560848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
560948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x2 */
561048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
561148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
561248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3x2dv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
561348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
561448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3 */
561548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
561648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
561748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3dv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
561848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
561948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat3x4 */
562048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
562148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
562248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix3x4dv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
562348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
562448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
562548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x2 */
562648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
562748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
562848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4x2dv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
562948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
563048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4x3 */
563148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
563248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
563348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4x3dv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
563448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
563548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* mat4 */
563648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
563748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
563848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
563948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniformMatrix4dv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
564048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
564148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
564248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
564348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
564448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
564548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
564648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
564748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
564848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
564948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 1)
565048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5651910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
5652910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
565348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
565448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
565548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
565648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
565748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
565848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
565948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
566048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
566148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
566248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
566348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
566448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
566548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
566648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
566748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
566848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedFP64Case3 : public ComputeShaderBase
566948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
567048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
567148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
567248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "FP64 support - subroutines";
567348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
567448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
567548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
567648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that subroutines that performs double precision computation works as expected in the CS.";
567748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
567848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
567948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
568048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL
568148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"Create and dispatch CS that uses double precision math functions in subroutines to compute output values.";
568248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
568348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
568448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
568548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
568648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
568748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
568848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
568948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
569048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
569148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
569248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
569348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
569448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
569548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
569648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
569748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
569848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
569948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
570048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "uniform double[4] g_input;" NL "uniform int index;" NL
570148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(std430, binding = 0) buffer Output {" NL "  double g_output[4];" NL "};" NL
570248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "subroutine double MathFunc(double x);" NL "subroutine uniform MathFunc g_func[4];" NL
570348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "subroutine(MathFunc)" NL "double Func0(double x) {" NL "  return abs(x);" // abs(-1.0LF) == 1.0LF
570448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "}" NL "subroutine(MathFunc)" NL "double Func1(double x) {" NL
570548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  return round(x);" // round(2.2LF) == 2.0LF
570648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "}" NL "subroutine(MathFunc)" NL "double Func2(double x) {" NL
570748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  return sign(x);" // sign(3.0LF) == 1.0LF
570848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "}" NL "subroutine(MathFunc)" NL "double Func3(double x) {" NL
570948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  return fract(x);" // fract(4.1LF) == 0.1LF
571048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "}" NL "void main() {" NL "  int i = index;" NL "  g_output[i] = g_func[i](g_input[i]);" NL "}";
571148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
571248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
571348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
571448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
571548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
571648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
571748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
571848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(double), NULL, GL_STATIC_DRAW);
571948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
572048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func0");
572148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func1");
572248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func2");
572348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func3");
572448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute0   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[0]");
572548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute1   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[1]");
572648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute2   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[2]");
572748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLint  loc_compute3   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[3]");
572848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
572948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
573048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
573148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// setup subroutines
573248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint indices[4];
573348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute0] = index_compute0;
573448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute1] = index_compute1;
573548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute2] = index_compute2;
573648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		indices[loc_compute3] = index_compute3;
573748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
573848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
573948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* set uniforms */
574048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
574148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble data[4] = { -1.0, 2.2, 3.0, 4.1 };
574248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glUniform1dv(glGetUniformLocation(m_program, "g_input"), 4, data);
574348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
574448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "index"), 0);
574548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
574648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "index"), 1);
574748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
574848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "index"), 2);
574948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
575048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1i(glGetUniformLocation(m_program, "index"), 3);
575148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
575248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
575348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
575448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
575548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
575648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLdouble expected[4] = { 1.0, 2.0, 1.0, 0.1 };
575748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLdouble	   data[4];
575848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
575948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
576048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int i = 0; i < 4; ++i)
576148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
576248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (fabs(data[i] - expected[i]) > g_color_eps.x())
576348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
5764910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					m_context.getTestContext().getLog()
5765910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be "
5766910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski						<< expected[i] << "." << tcu::TestLog::EndMessage;
576748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					return ERROR;
576848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
576948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
577048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
577148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
577248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
577348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
577448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
577548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
577648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
577748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
577848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
577948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
578048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
578148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
578248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass AdvancedConditionalDispatching : public ComputeShaderBase
578348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
578448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
578548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
578648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Conditional Dispatching";
578748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
578848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
578948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
579048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that DispatchCompute and DispatchComputeIndirect commands work as expected inside "
579148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "conditional blocks.";
579248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
579348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
579448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
579548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "1. Render two quads. One will pass depth-test and the second one will not." NL
579648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "2. Use GL_ANY_SAMPLES_PASSED query objects to 'remember' these results." NL
579748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "3. Use DispatchCompute and DispatchComputeIndirect commands inside conditional blocks using both "
579848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "query objects." NL
579948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "4. Verify that DispatchCompute and DispatchComputeIndirect commands are only executed in" NL
580048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "    the conditional block that uses query object that has passed depth-test.";
580148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
580248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
580348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
580448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Everything works as expected.";
580548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
580648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
580748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_vsfs;
580848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program_cs;
580948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_vertex_array;
581048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_query[2];
581148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
581248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
581348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
581448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
581548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
581648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_vsfs = 0;
581748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_cs   = 0;
581848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertex_array = 0;
581948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		memset(m_query, 0, sizeof(m_query));
582048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
582148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
582248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
582348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
582448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
582548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
582648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs = NL
582748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"uniform float g_depth;" NL "uniform vec2[3] g_vertex = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
582848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"void main() {" NL "  gl_Position = vec4(g_vertex[gl_VertexID], g_depth, 1);" NL "}";
582948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
583048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
583148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(0, 1, 0, 1);" NL "}";
583248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
583348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_vsfs = CreateProgram(glsl_vs, glsl_fs);
583448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program_vsfs);
583548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program_vsfs))
583648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
583748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
583848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
583948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  int g_output;" NL "};" NL
584048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  atomicAdd(g_output, 1);" NL "}";
584148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program_cs = CreateComputeProgram(glsl_cs);
584248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program_cs);
584348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program_cs))
584448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
584548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
584648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create storage buffer */
584748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
584848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const int data = 0;
584948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_storage_buffer);
585048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
585148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
585248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
585348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* create dispatch buffer */
585448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
585548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint data[3] = { 2, 2, 2 };
585648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &m_dispatch_buffer);
585748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
585848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
585948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
586048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
586148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenVertexArrays(1, &m_vertex_array);
586248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenQueries(2, m_query);
586348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
586448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEnable(GL_DEPTH_TEST);
586548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
586648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
586748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program_vsfs);
586848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindVertexArray(m_vertex_array);
586948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
587048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// this draw call will pass depth test
587148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[0]);
587248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.0f);
587348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLES, 0, 3);
587448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEndQuery(GL_ANY_SAMPLES_PASSED);
587548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
587648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// this draw call will NOT pass depth test
587748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[1]);
587848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.5f);
587948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDrawArrays(GL_TRIANGLES, 0, 3);
588048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEndQuery(GL_ANY_SAMPLES_PASSED);
588148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
588248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDisable(GL_DEPTH_TEST);
588348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
588448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program_cs);
588548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
588648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// these commands should be executed normally
588748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBeginConditionalRender(m_query[0], GL_QUERY_WAIT);
588848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(2, 2, 2);
588948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
589048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(0);
589148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEndConditionalRender();
589248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
589348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
589448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
589548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
589648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
589748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
589848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 16)
589948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5900910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
5901910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
590248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
590348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
590448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
590548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
590648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// these commands should be discarded
590748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBeginConditionalRender(m_query[1], GL_QUERY_WAIT);
590848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(2, 2, 2);
590948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
591048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(0);
591148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glEndConditionalRender();
591248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
591348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* validate */
591448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
591548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int data;
591648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
591748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
591848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data != 16 && m_context.getRenderContext().getRenderTarget().getDepthBits() != 0)
591948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5920910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
5921910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
592248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
592348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
592448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else if (data != 32 && m_context.getRenderContext().getRenderTarget().getDepthBits() == 0)
592548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
5926910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
5927910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data is " << data << " should be 32." << tcu::TestLog::EndMessage;
592848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
592948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
593048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
593148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
593248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
593348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
593448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
593548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
593648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
593748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
593848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
593948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
594048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
594148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
594248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_vsfs);
594348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program_cs);
594448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteVertexArrays(1, &m_vertex_array);
594548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteQueries(2, m_query);
594648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
594748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
594848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
594948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
595048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
595148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
595248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeAPINoActiveProgram : public ComputeShaderBase
595348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
595448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
595548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
595648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "API errors - no active program";
595748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
595848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
595948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
596048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the OpenGL API.";
596148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
596248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
596348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
596448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
596548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
596648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
596748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
596848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
596948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
597048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
597148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
597248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
597348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
597448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
597548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = 0;
597648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
597748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
597848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
597948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
598048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 2, 3);
598148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
598248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
5983910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
5984910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
5985910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "DispatchComputeIndirect if there is no active program for the compute\n"
5986910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "shader stage." << tcu::TestLog::EndMessage;
598748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
598848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
598948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
599048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* indirect dispatch */
599148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
599248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint		 buffer;
599348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint num_group[3] = { 3, 2, 1 };
599448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &buffer);
599548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
599648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
599748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
599848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteBuffers(1, &buffer);
599948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (glGetError() != GL_INVALID_OPERATION)
600048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
6001910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
6002910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6003910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "DispatchComputeIndirect if there is no active program for the compute\n"
6004910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "shader stage." << tcu::TestLog::EndMessage;
600548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
600648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
600748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
600848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
600948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
601048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL "  gl_Position = g_position;" NL "}";
601148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
601248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
601348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1);" NL "}";
601448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
601548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateProgram(glsl_vs, glsl_fs);
601648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
601748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
601848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
601948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
602048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
602148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
602248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 2, 3);
602348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
602448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6025910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6026910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6027910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "DispatchComputeIndirect if there is no active program for the compute\n"
6028910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "shader stage." << tcu::TestLog::EndMessage;
602948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
603048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
603148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
603248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* indirect dispatch */
603348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
603448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint		 buffer;
603548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const GLuint num_group[3] = { 3, 2, 1 };
603648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGenBuffers(1, &buffer);
603748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
603848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
603948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDispatchComputeIndirect(0);
604048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteBuffers(1, &buffer);
604148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (glGetError() != GL_INVALID_OPERATION)
604248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
6043910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
6044910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6045910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "DispatchComputeIndirect if there is no active program for the compute\n"
6046910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "shader stage." << tcu::TestLog::EndMessage;
604748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
604848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
604948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
605048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
605148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
605248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
605348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
605448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
605548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
605648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
605748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
605848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
605948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
606048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
606148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeAPIWorkGroupCount : public ComputeShaderBase
606248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
606348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
606448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
606548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "API errors - invalid work group count";
606648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
606748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
606848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
606948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the OpenGL API.";
607048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
607148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
607248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
607348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
607448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
607548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
607648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
607748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
607848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
607948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
608048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
608148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
608248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
608348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
608448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
608548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
608648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
608748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
608848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
608948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
609048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
609148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
609248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
609348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL
609448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_output[gl_GlobalInvocationID.x * gl_GlobalInvocationID.y * gl_GlobalInvocationID.z] = 0;" NL "}";
609548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
609648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
609748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
609848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
609948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
610048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
610148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
610248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
610348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
610448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint x, y, z;
610548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
610648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
610748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
610848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
610948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
611048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
611148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(x + 1, 1, 1);
611248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_VALUE)
611348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6114910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6115910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6116910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6117910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
611848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
611948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
612048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
612148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, y + 1, 1);
612248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_VALUE)
612348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6124910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6125910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6126910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6127910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
612848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
612948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
613048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
613148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, z + 1);
613248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_VALUE)
613348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6134910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6135910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6136910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6137910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
613848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
613948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
614048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
614148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
614248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
614348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
614448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
614548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
614648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
614748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
614848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
614948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
615048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
615148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
615248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeAPIIndirect : public ComputeShaderBase
615348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
615448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
615548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
615648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "API errors - incorrect DispatchComputeIndirect usage";
615748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
615848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
615948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
616048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the OpenGL API.";
616148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
616248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
616348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
616448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
616548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
616648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
616748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
616848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
616948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
617048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
617148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
617248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
617348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_dispatch_buffer;
617448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
617548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
617648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
617748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		  = 0;
617848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer  = 0;
617948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_dispatch_buffer = 0;
618048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
618148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
618248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
618348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
618448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
618548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
618648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
618748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
618848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
618948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
619048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
619148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
619248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
619348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
619448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
619548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
619648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
619748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint num_groups[6] = { 1, 1, 1, 1, 1, 1 };
619848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_dispatch_buffer);
619948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
620048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_COPY);
620148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
620248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
620348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
620448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(-2);
620548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_VALUE)
620648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6207910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6208910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6209910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
621048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
621148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
621248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
621348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(3);
621448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_VALUE)
621548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6216910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6217910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6218910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
621948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
622048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
622148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
622248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(16);
622348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
622448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6225910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6226910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message
6227910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6228910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6229910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
623048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
623148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
623248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
623348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
623448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchComputeIndirect(0);
623548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
623648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6237910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6238910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message
6239910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6240910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6241910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
624248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
624348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
624448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
624548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
624648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
624748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
624848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
624948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
625048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
625148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
625248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_dispatch_buffer);
625348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
625448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
625548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
625648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
625748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeAPIProgram : public ComputeShaderBase
625848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
625948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
626048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
626148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "API errors - program state";
626248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
626348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
626448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
626548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the OpenGL API.";
626648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
626748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
626848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
626948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
627048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
627148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
627248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
627348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
627448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
627548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
627648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
627748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
627848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
627948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
628048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
628148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
628248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
628348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
628448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
628548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
628648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
628748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_vs =
628848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL "  gl_Position = g_position;" NL "}";
628948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
629048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_fs =
629148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1);" NL "}";
629248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateProgram(glsl_vs, glsl_fs);
629348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
629448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint v[3];
629548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
629648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
629748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6298910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6299910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6300910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6301910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
630248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
630348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
630448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
630548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
630648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
630748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
630848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
630948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
631048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (glGetError() != GL_INVALID_OPERATION)
631148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6312910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6313910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6314910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6315910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
631648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
631748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
631848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
631948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
632048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
632148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
632248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			"  uint g_output[];" NL "};" NL "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
632348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = glCreateProgram();
632448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
632548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
632648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(m_program, sh);
632748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
632848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &glsl_cs, NULL);
632948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
633048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
633148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		sh = glCreateShader(GL_VERTEX_SHADER);
633248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(m_program, sh);
633348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
633448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &glsl_vs, NULL);
633548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
633648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
633748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		sh = glCreateShader(GL_FRAGMENT_SHADER);
633848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glAttachShader(m_program, sh);
633948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
634048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &glsl_fs, NULL);
634148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
634248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
634348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
634448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint status;
634548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(m_program, GL_LINK_STATUS, &status);
634648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (status == GL_TRUE)
634748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6348910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6349910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "LinkProgram will fail if <program> contains a combination"
6350910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< " of compute and\n non-compute shaders.\n"
6351910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::EndMessage;
635248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
635348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
635448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
635548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
635648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
635748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
635848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
635948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
636048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
636148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
636248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
636348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
636448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
636548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
636648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeGLSLCompileTimeErrors : public ComputeShaderBase
636748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
636848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
636948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
637048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Compile-time errors";
637148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
637248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
637348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
637448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the GLSL compiler.";
637548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
637648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
637748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
637848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
637948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
638048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
638148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
638248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
638348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
638448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
638548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	static std::string Shader1(int x, int y, int z)
638648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
638748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		std::stringstream ss;
638848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ss << "#version 430 core" NL "layout(local_size_x = " << x << ", local_size_y = " << y
638948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		   << ", local_size_z = " << z << ") in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
639048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos										  "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
639148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return ss.str();
639248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
639348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
639448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
639548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// gl_GlobalInvocationID requires "#version 430" or later or GL_ARB_compute_shader
639648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// extension enabled
639748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Compile("#version 420 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
639848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  uint g_output[];" NL "};" NL "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL
639948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "}"))
640048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
640148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
640248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(local_size_x = 2) in;" NL
640348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
640448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
640548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
640648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
640748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "in uint x;" NL
640848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
640948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  g_output[gl_GlobalInvocationID.x] = x;" NL "}"))
641048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
641148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
641248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "out uint x;" NL
641348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
641448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					 "  g_output[gl_GlobalInvocationID.x] = 0;" NL "  x = 0;" NL "}"))
641548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
641648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
641748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
641848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint x, y, z;
641948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &x);
642048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &y);
642148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &z);
642248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
642348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!Compile(Shader1(x + 1, 1, 1)))
642448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
642548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!Compile(Shader1(1, y + 1, 1)))
642648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
642748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!Compile(Shader1(1, 1, z + 1)))
642848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return ERROR;
642948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
643048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
643148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
643248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
643348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
643448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool Compile(const std::string& source)
643548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
643648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
643748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
643848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const src = source.c_str();
643948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glShaderSource(sh, 1, &src, NULL);
644048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glCompileShader(sh);
644148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
644248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLchar log[1024];
644348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetShaderInfoLog(sh, sizeof(log), NULL, log);
6444910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
6445910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski											<< log << tcu::TestLog::EndMessage;
644648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
644748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint status;
644848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
644948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteShader(sh);
645048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
645148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (status == GL_TRUE)
645248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6453910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6454910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage;
645548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
645648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
645748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
645848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
645948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
646048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
646148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
646248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass NegativeGLSLLinkTimeErrors : public ComputeShaderBase
646348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
646448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
646548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
646648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Link-time errors";
646748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
646848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
646948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
647048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that appropriate errors are generated by the GLSL linker.";
647148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
647248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
647348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
647448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
647548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
647648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
647748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
647848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
647948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
648048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
648148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
648248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
648348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// no layout
648448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Link("#version 430 core" NL "void Run();" NL "void main() {" NL "  Run();" NL "}",
648548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "#version 430 core" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
648648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "void Run() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
648748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
648848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
648948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!Link("#version 430 core" NL "layout(local_size_x = 2) in;" NL "void Run();" NL "void main() {" NL
649048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "  Run();" NL "}",
649148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
649248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "  uint g_output[];" NL "};" NL "void Run() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
649348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
649448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
649548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
649648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
649748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
649848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool Link(const std::string& cs0, const std::string& cs1)
649948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
650048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const GLuint p = glCreateProgram();
650148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
650248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* shader 0 */
650348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
650448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
650548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(p, sh);
650648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
650748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const src = cs0.c_str();
650848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 1, &src, NULL);
650948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
651048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
651148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint status;
651248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
651348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (status == GL_FALSE)
651448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
651548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glDeleteProgram(p);
6516910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
6517910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "CS0 compilation should be ok." << tcu::TestLog::EndMessage;
651848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
651948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
652048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
652148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		/* shader 1 */
652248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
652348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
652448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glAttachShader(p, sh);
652548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glDeleteShader(sh);
652648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* const src = cs1.c_str();
652748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glShaderSource(sh, 1, &src, NULL);
652848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glCompileShader(sh);
652948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
653048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLint status;
653148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
653248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (status == GL_FALSE)
653348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
653448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				glDeleteProgram(p);
6535910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
6536910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "CS1 compilation should be ok." << tcu::TestLog::EndMessage;
653748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
653848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
653948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
654048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
654148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(p);
654248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
654348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLchar log[1024];
654448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramInfoLog(p, sizeof(log), NULL, log);
6545910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
6546910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski											<< log << tcu::TestLog::EndMessage;
654748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
654848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLint status;
654948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGetProgramiv(p, GL_LINK_STATUS, &status);
655048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(p);
655148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
655248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (status == GL_TRUE)
655348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
6554910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski			m_context.getTestContext().getLog()
6555910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				<< tcu::TestLog::Message << "Link operation should fail." << tcu::TestLog::EndMessage;
655648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return false;
655748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
655848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
655948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
656048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
656148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
656248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
656348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosclass BasicWorkGroupSizeIsConst : public ComputeShaderBase
656448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
656548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Title()
656648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
656748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "gl_WorkGroupSize is an constant";
656848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
656948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Purpose()
657048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
657148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "Verify that gl_WorkGroupSize can be used as an constant expression.";
657248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
657348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string Method()
657448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
657548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
657648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
657748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual std::string PassCriteria()
657848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
657948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NL "";
658048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
658148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
658248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_program;
658348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLuint m_storage_buffer;
658448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
658548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Setup()
658648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
658748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program		 = 0;
658848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_storage_buffer = 0;
658948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
659048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
659148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
659248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Run()
659348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
659448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char* const glsl_cs =
659548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			NL "layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;" NL
659648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "layout(std430, binding = 0) buffer Output {" NL "  uint g_buffer[22 + gl_WorkGroupSize.x];" NL "};" NL
659748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "shared uint g_shared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];" NL
659848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "uniform uint g_uniform[gl_WorkGroupSize.z + 20] = { "
659948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };" NL "void main() {" NL
660048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_shared[gl_LocalInvocationIndex] = 1U;" NL "  groupMemoryBarrier();" NL "  barrier();" NL
660148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  uint sum = 0;" NL
660248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  for (uint i = 0; i < gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z; ++i) {" NL
660348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "    sum += g_shared[i];" NL "  }" NL "  sum += g_uniform[gl_LocalInvocationIndex];" NL
660448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			   "  g_buffer[gl_LocalInvocationIndex] = sum;" NL "}";
660548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_program = CreateComputeProgram(glsl_cs);
660648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glLinkProgram(m_program);
660748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!CheckProgram(m_program))
660848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			return ERROR;
660948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
661048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glGenBuffers(1, &m_storage_buffer);
661148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
661248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBufferData(GL_SHADER_STORAGE_BUFFER, 24 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
661348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
661448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(m_program);
661548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDispatchCompute(1, 1, 1);
661648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
661748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
661848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		long	error = NO_ERROR;
661948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		GLuint* data;
662048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
662148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		data =
662248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 24, GL_MAP_READ_BIT));
662348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (GLuint i = 0; i < 24; ++i)
662448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
662548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (data[i] != (i + 25))
662648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
6627910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski				m_context.getTestContext().getLog()
6628910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << i + 25
6629910dcf5adcc9b50cb1ca75369927bbd44c231c37Piotr Byszewski					<< "." << tcu::TestLog::EndMessage;
663048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				error = ERROR;
663148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
663248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
663348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
663448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
663548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return error;
663648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
663748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
663848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	virtual long Cleanup()
663948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
664048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glUseProgram(0);
664148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteProgram(m_program);
664248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		glDeleteBuffers(1, &m_storage_buffer);
664348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return NO_ERROR;
664448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
664548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
664648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
664748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos} // anonymous namespace
664848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
664948087f5f0eb08759ee763f98daf3b34becb74559Pyry HaulosComputeShaderTests::ComputeShaderTests(deqp::Context& context) : TestCaseGroup(context, "compute_shader", "")
665048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
665148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
665248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
665348087f5f0eb08759ee763f98daf3b34becb74559Pyry HaulosComputeShaderTests::~ComputeShaderTests(void)
665448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
665548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
665648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
665748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosvoid ComputeShaderTests::init()
665848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
665948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	using namespace deqp;
666048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "simple-compute", TestSubcase::Create<SimpleCompute>));
666148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "one-work-group", TestSubcase::Create<BasicOneWorkGroup>));
666248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-ubo", TestSubcase::Create<BasicResourceUBO>));
666348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-texture", TestSubcase::Create<BasicResourceTexture>));
666448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-image", TestSubcase::Create<BasicResourceImage>));
666548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-atomic-counter", TestSubcase::Create<BasicResourceAtomicCounter>));
666648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-subroutine", TestSubcase::Create<BasicResourceSubroutine>));
666748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resource-uniform", TestSubcase::Create<BasicResourceUniform>));
666848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "built-in-variables", TestSubcase::Create<BasicBuiltinVariables>));
666948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "max", TestSubcase::Create<BasicMax>));
667048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "work-group-size", TestSubcase::Create<BasicWorkGroupSizeIsConst>));
667148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "build-monolithic", TestSubcase::Create<BasicBuildMonolithic>));
667248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "build-separable", TestSubcase::Create<BasicBuildSeparable>));
667348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "shared-simple", TestSubcase::Create<BasicSharedSimple>));
667448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "shared-struct", TestSubcase::Create<BasicSharedStruct>));
667548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "dispatch-indirect", TestSubcase::Create<BasicDispatchIndirect>));
667648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "sso-compute-pipeline", TestSubcase::Create<BasicSSOComputePipeline>));
667748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "sso-case2", TestSubcase::Create<BasicSSOCase2>));
667848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "sso-case3", TestSubcase::Create<BasicSSOCase3>));
667948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "atomic-case1", TestSubcase::Create<BasicAtomicCase1>));
668048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "atomic-case2", TestSubcase::Create<BasicAtomicCase2>));
668148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "atomic-case3", TestSubcase::Create<BasicAtomicCase3>));
668248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "copy-image", TestSubcase::Create<AdvancedCopyImage>));
668348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "pipeline-pre-vs", TestSubcase::Create<AdvancedPipelinePreVS>));
668448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(
668548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		new TestSubcase(m_context, "pipeline-gen-draw-commands", TestSubcase::Create<AdvancedPipelineGenDrawCommands>));
668648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "pipeline-compute-chain", TestSubcase::Create<AdvancedPipelineComputeChain>));
668748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "pipeline-post-fs", TestSubcase::Create<AdvancedPipelinePostFS>));
668848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "pipeline-post-xfb", TestSubcase::Create<AdvancedPipelinePostXFB>));
668948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "shared-indexing", TestSubcase::Create<AdvancedSharedIndexing>));
669048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "shared-max", TestSubcase::Create<AdvancedSharedMax>));
669148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "dynamic-paths", TestSubcase::Create<AdvancedDynamicPaths>));
669248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "resources-max", TestSubcase::Create<AdvancedResourcesMax>));
669348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "fp64-case1", TestSubcase::Create<AdvancedFP64Case1>));
669448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "fp64-case2", TestSubcase::Create<AdvancedFP64Case2>));
669548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "fp64-case3", TestSubcase::Create<AdvancedFP64Case3>));
669648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(
669748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		new TestSubcase(m_context, "conditional-dispatching", TestSubcase::Create<AdvancedConditionalDispatching>));
669848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "api-no-active-program", TestSubcase::Create<NegativeAPINoActiveProgram>));
669948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "api-work-group-count", TestSubcase::Create<NegativeAPIWorkGroupCount>));
670048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "api-indirect", TestSubcase::Create<NegativeAPIIndirect>));
670148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "api-program", TestSubcase::Create<NegativeAPIProgram>));
670248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(
670348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		new TestSubcase(m_context, "glsl-compile-time-errors", TestSubcase::Create<NegativeGLSLCompileTimeErrors>));
670448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	addChild(new TestSubcase(m_context, "glsl-link-time-errors", TestSubcase::Create<NegativeGLSLLinkTimeErrors>));
670548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
670648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos} // gl4cts namespace
6707