13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program OpenGL ES 3.1 Module
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * -------------------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Shader atomic operation tests.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "es31fShaderAtomicOpTests.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluShaderProgram.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluShaderUtil.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluRenderContext.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluObjectWrapper.hpp"
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluProgramInterfaceQuery.hpp"
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVector.hpp"
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTestLog.hpp"
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVectorUtil.hpp"
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFormatUtil.hpp"
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deStringUtil.hpp"
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deRandom.hpp"
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwFunctions.hpp"
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwEnums.hpp"
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <algorithm>
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <set>
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace deqp
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace gles31
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace Functional
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::string;
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector;
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::TestLog;
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::UVec3;
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::set;
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace glu;
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T, int Size>
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline T product (const tcu::Vector<T, Size>& v)
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	T res = v[0];
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 1; ndx < Size; ndx++)
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		res *= v[ndx];
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicOpCase : public TestCase
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							ShaderAtomicOpCase	(Context& context, const char* name, const char* funcName, AtomicOperandType operandType, DataType type, Precision precision, const UVec3& workGroupSize);
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							~ShaderAtomicOpCase	(void);
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					init				(void);
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					deinit				(void);
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult			iterate				(void);
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual void			getInputs			(int numValues, int stride, void* inputs) const = 0;
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual bool			verify				(int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const = 0;
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const string			m_funcName;
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperandType	m_operandType;
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const DataType			m_type;
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const Precision			m_precision;
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const UVec3				m_workGroupSize;
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const UVec3				m_numWorkGroups;
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32				m_initialValue;
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							ShaderAtomicOpCase	(const ShaderAtomicOpCase& other);
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicOpCase&		operator=			(const ShaderAtomicOpCase& other);
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderProgram*			m_program;
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
963c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpCase::ShaderAtomicOpCase (Context& context, const char* name, const char* funcName, AtomicOperandType operandType, DataType type, Precision precision, const UVec3& workGroupSize)
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCase			(context, name, funcName)
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_funcName		(funcName)
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_operandType		(operandType)
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_type			(type)
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_precision		(precision)
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_workGroupSize	(workGroupSize)
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_numWorkGroups	(4,4,4)
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_initialValue	(0)
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_program			(DE_NULL)
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1093c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpCase::~ShaderAtomicOpCase (void)
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicOpCase::deinit();
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderAtomicOpCase::init (void)
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			isSSBO		= m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE;
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			precName	= getPrecisionName(m_precision);
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			typeName	= getDataTypeName(m_type);
11975be7fae1949a801c080530de53bdf123abb517aPyry Haulos
12075be7fae1949a801c080530de53bdf123abb517aPyry Haulos	const DataType		outType		= isSSBO ? m_type : glu::TYPE_UINT;
12175be7fae1949a801c080530de53bdf123abb517aPyry Haulos	const char*			outTypeName	= getDataTypeName(outType);
12275be7fae1949a801c080530de53bdf123abb517aPyry Haulos
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32		numValues	= product(m_workGroupSize)*product(m_numWorkGroups);
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "#version 310 es\n"
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "layout(local_size_x = " << m_workGroupSize.x()
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< ", local_size_y = " << m_workGroupSize.y()
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< ", local_size_z = " << m_workGroupSize.z() << ") in;\n"
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "layout(binding = 0) buffer InOut\n"
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " inputValues[" << numValues << "];\n"
13375be7fae1949a801c080530de53bdf123abb517aPyry Haulos		<< "	" << precName << " " << outTypeName << " outputValues[" << numValues << "];\n"
13475be7fae1949a801c080530de53bdf123abb517aPyry Haulos		<< "	" << (isSSBO ? "coherent " : "") << precName << " " << outTypeName << " groupValues[" << product(m_numWorkGroups) << "];\n"
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "} sb_inout;\n";
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!isSSBO)
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "shared " << precName << " " << typeName << " s_var;\n";
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n"
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "void main (void)\n"
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint localSize  = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n"
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint globalNdx  = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint globalOffs = localSize*globalNdx;\n"
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint offset     = globalOffs + gl_LocalInvocationIndex;\n"
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n";
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (isSSBO)
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15175be7fae1949a801c080530de53bdf123abb517aPyry Haulos		DE_ASSERT(outType == m_type);
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "	sb_inout.outputValues[offset] = " << m_funcName << "(sb_inout.groupValues[globalNdx], sb_inout.inputValues[offset]);\n";
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15675be7fae1949a801c080530de53bdf123abb517aPyry Haulos		const string		castBeg	= outType != m_type ? (string(outTypeName) + "(") : string("");
15775be7fae1949a801c080530de53bdf123abb517aPyry Haulos		const char* const	castEnd	= outType != m_type ? ")" : "";
15875be7fae1949a801c080530de53bdf123abb517aPyry Haulos
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "	if (gl_LocalInvocationIndex == 0u)\n"
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "		s_var = " << typeName << "(" << tcu::toHex(m_initialValue) << "u);\n"
1618852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			<< "	barrier();\n"
16275be7fae1949a801c080530de53bdf123abb517aPyry Haulos			<< "	" << precName << " " << typeName << " res = " << m_funcName << "(s_var, sb_inout.inputValues[offset]);\n"
16375be7fae1949a801c080530de53bdf123abb517aPyry Haulos			<< "	sb_inout.outputValues[offset] = " << castBeg << "res" << castEnd << ";\n"
1648852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			<< "	barrier();\n"
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "	if (gl_LocalInvocationIndex == 0u)\n"
16675be7fae1949a801c080530de53bdf123abb517aPyry Haulos			<< "		sb_inout.groupValues[globalNdx] = " << castBeg << "s_var" << castEnd << ";\n";
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!m_program);
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_program = new ShaderProgram(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str()));
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_testCtx.getLog() << *m_program;
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_program->isOk())
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		delete m_program;
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_program = DE_NULL;
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::TestError("Compile failed");
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderAtomicOpCase::deinit (void)
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	delete m_program;
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_program = DE_NULL;
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1903c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpCase::IterateResult ShaderAtomicOpCase::iterate (void)
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				program			= m_program->getProgram();
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const Buffer				inoutBuffer		(m_context.getRenderContext());
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				blockNdx		= gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "InOut");
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceBlockInfo	blockInfo		= getProgramInterfaceBlockInfo(gl, program, GL_SHADER_STORAGE_BLOCK, blockNdx);
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				inVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.inputValues[0]");
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	inVarInfo		= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, inVarNdx);
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				outVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.outputValues[0]");
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	outVarInfo		= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, outVarNdx);
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				groupVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.groupValues[0]");
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	groupVarInfo	= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, groupVarNdx);
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				numValues		= product(m_workGroupSize)*product(m_numWorkGroups);
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(inVarInfo.arraySize == numValues &&
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  outVarInfo.arraySize == numValues &&
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  groupVarInfo.arraySize == product(m_numWorkGroups));
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.useProgram(program);
2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup buffer.
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<deUint8> bufData(blockInfo.dataSize);
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::fill(bufData.begin(), bufData.end(), 0);
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getInputs((int)numValues, (int)inVarInfo.arrayStride, &bufData[0] + inVarInfo.offset);
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE)
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (deUint32 valNdx = 0; valNdx < product(m_numWorkGroups); valNdx++)
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				*(deUint32*)(&bufData[0] + groupVarInfo.offset + groupVarInfo.arrayStride*valNdx) = m_initialValue;
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inoutBuffer);
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockInfo.dataSize, &bufData[0], GL_STATIC_READ);
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *inoutBuffer);
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed");
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.dispatchCompute(m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back and compare
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const void*		resPtr		= gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, blockInfo.dataSize, GL_MAP_READ_BIT);
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool			isOk		= true;
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(resPtr);
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		isOk = verify((int)numValues,
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					  (int)inVarInfo.arrayStride, (const deUint8*)resPtr + inVarInfo.offset,
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					  (int)outVarInfo.arrayStride, (const deUint8*)resPtr + outVarInfo.offset,
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					  (int)groupVarInfo.arrayStride, (const deUint8*)resPtr + groupVarInfo.offset);
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								isOk ? "Pass"				: "Comparison failed");
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return STOP;
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicAddCase : public ShaderAtomicOpCase
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicAddCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicAdd", operandType, type, precision, UVec3(3,2,1))
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = 1;
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random	rnd			(deStringHash(getName()));
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	maxVal		= m_precision == PRECISION_LOWP ? 2 : 32;
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	minVal		= 1;
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \todo [2013-09-04 pyry] Negative values!
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < numValues; valNdx++)
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(int*)((deUint8*)inputs + stride*valNdx) = rnd.getInt(minVal, maxVal);
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOffset		= groupNdx*workGroupSize;
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOutput		= *(const int*)((const deUint8*)groupOutputs + groupNdx*groupStride);
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			set<int>	outValues;
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool		maxFound		= false;
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int			valueSum		= (int)m_initialValue;
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int inputValue = *(const int*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				valueSum += inputValue;
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (groupOutput != valueSum)
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected sum " << valueSum << ", got " << groupOutput << TestLog::EndMessage;
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	inputValue		= *(const int*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	outputValue		= *(const int*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!de::inRange(outputValue, (int)m_initialValue, valueSum-inputValue))
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": expected value in range [" << m_initialValue << ", " << (valueSum-inputValue)
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << "], got " << outputValue
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (outValues.find(outputValue) != outValues.end())
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found duplicate value " << outputValue
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				outValues.insert(outputValue);
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (outputValue == valueSum-inputValue)
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					maxFound = true;
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (!maxFound)
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: could not find maximum expected value from group " << groupNdx << TestLog::EndMessage;
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (outValues.find((int)m_initialValue) == outValues.end())
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx << TestLog::EndMessage;
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
346664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
347664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyrystatic int getPrecisionNumIntegerBits (glu::Precision precision)
348664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry{
349664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	switch (precision)
350664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	{
351664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		case glu::PRECISION_HIGHP:		return 32;
352664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		case glu::PRECISION_MEDIUMP:	return 16;
353664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		case glu::PRECISION_LOWP:		return 9;
354664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		default:
355664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			DE_ASSERT(false);
356664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			return 0;
357664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	}
358664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry}
359664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
360664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyrystatic deUint32 getPrecisionMask (int numPreciseBits)
361664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry{
362664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	// \note: bit shift with larger or equal than var length is undefined, use 64 bit ints
363664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	return (deUint32)((((deUint64)1u) << numPreciseBits) - 1) ;
364664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry}
365664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
366664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyrystatic bool intEqualsAfterUintCast (deInt32 value, deUint32 casted, glu::Precision precision)
367664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry{
368664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	// Bit format of 'casted' = [ uint -> highp uint promotion bits (0) ] [ sign extend bits (s) ] [ value bits ]
369664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	//                                                                                             |--min len---|
370664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	//                                                                    |---------------signed length---------|
371664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	//                          |-------------------------------- highp uint length ----------------------------|
372664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
373664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	const deUint32	reference		= (deUint32)value;
374664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	const int		signBitOn		= value < 0;
375664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	const int		numPreciseBits	= getPrecisionNumIntegerBits(precision);
376664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	const deUint32	preciseMask		= getPrecisionMask(numPreciseBits);
377664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
378664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	// Lowest N bits must match, N = minimum precision
379664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	if ((reference & preciseMask) != (casted & preciseMask))
380664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		return false;
381664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
382664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	// Other lowest bits must match the sign and the remaining (topmost) if any must be 0
383664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	for (int signedIntegerLength = numPreciseBits; signedIntegerLength <= 32; ++signedIntegerLength)
384664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	{
385664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		const deUint32 signBits = (signBitOn) ? (getPrecisionMask(signedIntegerLength)) : (0u);
386664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
387664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		if ((signBits & ~preciseMask) == (casted & ~preciseMask))
388664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			return true;
389664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	}
390664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	return false;
391664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry}
392664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
393664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyrystatic bool containsAfterUintCast (const std::set<deInt32>& haystack, deUint32 needle, glu::Precision precision)
394664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry{
395664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	for (std::set<deInt32>::const_iterator it = haystack.begin(); it != haystack.end(); ++it)
396664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		if (intEqualsAfterUintCast(*it, needle, precision))
397664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			return true;
398664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	return false;
399664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry}
400664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
401664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyrystatic bool containsAfterUintCast (const std::set<deUint32>& haystack, deInt32 needle, glu::Precision precision)
402664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry{
403664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	for (std::set<deUint32>::const_iterator it = haystack.begin(); it != haystack.end(); ++it)
404664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		if (intEqualsAfterUintCast(needle, *it, precision))
405664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			return true;
406664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry	return false;
407664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry}
408664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicMinCase : public ShaderAtomicOpCase
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicMinCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicMin", operandType, type, precision, UVec3(3,2,1))
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = m_precision == PRECISION_LOWP ? 100 : 1000;
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random	rnd			(deStringHash(getName()));
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool	isSigned	= m_type == TYPE_INT;
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	maxVal		= m_precision == PRECISION_LOWP ? 100 : 1000;
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	minVal		= isSigned ? -maxVal : 0;
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < numValues; valNdx++)
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(int*)((deUint8*)inputs + stride*valNdx) = rnd.getInt(minVal, maxVal);
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
434664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		bool		anyError		= false;
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
438664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			const int		groupOffset		= groupNdx*workGroupSize;
439664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			const deUint32	groupOutput		= *(const deUint32*)((const deUint8*)groupOutputs + groupNdx*groupStride);
440664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			set<deInt32>	inValues;
441664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			set<deUint32>	outValues;
442664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			int				minValue		= (int)m_initialValue;
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
446664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				const deInt32 inputValue = *(const deInt32*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				inValues.insert(inputValue);
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				minValue = de::min(inputValue, minValue);
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
451664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			if (!intEqualsAfterUintCast(minValue, groupOutput, m_precision))
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
453664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				m_testCtx.getLog()
454664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< TestLog::Message
455664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< "ERROR: at group " << groupNdx
456664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< ": expected minimum " << minValue << " (" << tcu::Format::Hex<8>((deUint32)minValue) << ")"
457664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< ", got " << groupOutput << " (" << tcu::Format::Hex<8>(groupOutput) << ")"
458664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< TestLog::EndMessage;
459664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				anyError = true;
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
464664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				const deUint32 outputValue = *(const deUint32*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
466664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				if (!containsAfterUintCast(inValues, outputValue, m_precision) &&
467664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					!intEqualsAfterUintCast((deInt32)m_initialValue, outputValue, m_precision))
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << outputValue
471664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry														   << " (" << tcu::Format::Hex<8>(outputValue) << ")"
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
473664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					anyError = true;
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				outValues.insert(outputValue);
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
479664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			if (!containsAfterUintCast(outValues, (int)m_initialValue, m_precision))
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx << TestLog::EndMessage;
482664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				anyError = true;
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
486664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		return !anyError;
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicMaxCase : public ShaderAtomicOpCase
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicMaxCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicMax", operandType, type, precision, UVec3(3,2,1))
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool isSigned = m_type == TYPE_INT;
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = isSigned ? (m_precision == PRECISION_LOWP ? -100 : -1000) : 0;
4983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random	rnd			(deStringHash(getName()));
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool	isSigned	= m_type == TYPE_INT;
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	maxVal		= m_precision == PRECISION_LOWP ? 100 : 1000;
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	minVal		= isSigned ? -maxVal : 0;
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < numValues; valNdx++)
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(int*)((deUint8*)inputs + stride*valNdx) = rnd.getInt(minVal, maxVal);
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
516664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		bool		anyError		= false;
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
520664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			const int		groupOffset		= groupNdx*workGroupSize;
521664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			const deUint32	groupOutput		= *(const deUint32*)((const deUint8*)groupOutputs + groupNdx*groupStride);
522664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			set<int>		inValues;
523664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			set<deUint32>	outValues;
524664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			int				maxValue		= (int)m_initialValue;
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
528664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				const deInt32 inputValue = *(const deInt32*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				inValues.insert(inputValue);
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				maxValue = de::max(maxValue, inputValue);
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
533664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			if (!intEqualsAfterUintCast(maxValue, groupOutput, m_precision))
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
535664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				m_testCtx.getLog()
536664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< TestLog::Message
537664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< "ERROR: at group " << groupNdx
538664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< ": expected maximum " << maxValue << " (" << tcu::Format::Hex<8>((deUint32)maxValue) << ")"
539664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< ", got " << groupOutput << " (" << tcu::Format::Hex<8>(groupOutput) << ")"
540664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					<< TestLog::EndMessage;
541664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				anyError = true;
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
546664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				const deUint32 outputValue = *(const deUint32*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
548664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				if (!containsAfterUintCast(inValues, outputValue, m_precision) &&
549664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					!intEqualsAfterUintCast((deInt32)m_initialValue, outputValue, m_precision))
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << outputValue
553664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry														   << " (" << tcu::Format::Hex<8>(outputValue) << ")"
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
555664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry					anyError = true;
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				outValues.insert(outputValue);
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
561664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry			if (!containsAfterUintCast(outValues, (int)m_initialValue, m_precision))
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx << TestLog::EndMessage;
564664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry				anyError = true;
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
568664e0500b4d1458fae75baf99cc4368442a0f370Jarkko Pöyry		return !anyError;
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicAndCase : public ShaderAtomicOpCase
5733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicAndCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicAnd", operandType, type, precision, UVec3(3,2,1))
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numBits		= m_precision == PRECISION_HIGHP ? 32 :
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									  m_precision == PRECISION_MEDIUMP ? 16 : 8;
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	valueMask	= numBits == 32 ? ~0u : (1u<<numBits)-1u;
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = ~((1u<<(numBits-1u)) | 1u) & valueMask; // All bits except lowest and highest set.
5823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5843c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
5853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
5863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random		rnd				(deStringHash(getName()));
5883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		workGroupSize	= (int)product(m_workGroupSize);
5893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numWorkGroups	= numValues/workGroupSize;
5903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numBits			= m_precision == PRECISION_HIGHP ? 32 :
5913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										  m_precision == PRECISION_MEDIUMP ? 16 : 8;
5923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	valueMask		= numBits == 32 ? ~0u : (1u<<numBits)-1u;
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		groupOffset		= groupNdx*workGroupSize;
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	groupMask		= 1<<rnd.getInt(0, numBits-2); // One bit is always set.
5983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				*(deUint32*)((deUint8*)inputs + stride*(groupOffset+localNdx)) = (rnd.getUint32() & valueMask) | groupMask;
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		groupOffset		= groupNdx*workGroupSize;
6123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	groupOutput		= *(const deUint32*)((const deUint8*)groupOutputs + groupNdx*groupStride);
6133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deUint32		expectedValue	= m_initialValue;
6143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 inputValue = *(const deUint32*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
6183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				expectedValue &= inputValue;
6193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (expectedValue != groupOutput)
6223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected " << tcu::toHex(expectedValue) << ", got " << tcu::toHex(groupOutput) << TestLog::EndMessage;
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
6253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 outputValue = *(const deUint32*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if ((outputValue & ~m_initialValue) != 0)
6323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
6333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
6343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << tcu::toHex(outputValue)
6353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
6363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
6373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
6423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicOrCase : public ShaderAtomicOpCase
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicOrCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicOr", operandType, type, precision, UVec3(3,2,1))
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = 1u; // Lowest bit set.
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
6553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random		rnd				(deStringHash(getName()));
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		workGroupSize	= (int)product(m_workGroupSize);
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numWorkGroups	= numValues/workGroupSize;
6603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numBits			= m_precision == PRECISION_HIGHP ? 32 :
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										  m_precision == PRECISION_MEDIUMP ? 16 : 8;
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int groupOffset = groupNdx*workGroupSize;
6663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				*(deUint32*)((deUint8*)inputs + stride*(groupOffset+localNdx)) = 1u<<rnd.getInt(0, numBits-1);
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		groupOffset		= groupNdx*workGroupSize;
6803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	groupOutput		= *(const deUint32*)((const deUint8*)groupOutputs + groupNdx*groupStride);
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deUint32		expectedValue	= m_initialValue;
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 inputValue = *(const deUint32*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				expectedValue |= inputValue;
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (expectedValue != groupOutput)
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected " << tcu::toHex(expectedValue) << ", got " << tcu::toHex(groupOutput) << TestLog::EndMessage;
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 outputValue = *(const deUint32*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if ((outputValue & m_initialValue) == 0)
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << tcu::toHex(outputValue)
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicXorCase : public ShaderAtomicOpCase
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7153c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
7163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicXorCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
7173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicXor", operandType, type, precision, UVec3(3,2,1))
7183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = 0;
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random		rnd				(deStringHash(getName()));
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		workGroupSize	= (int)product(m_workGroupSize);
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numWorkGroups	= numValues/workGroupSize;
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int groupOffset = groupNdx*workGroupSize;
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// First uses random bit-pattern.
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(deUint32*)((deUint8*)inputs + stride*(groupOffset)) = rnd.getUint32();
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Rest have either all or no bits set.
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 1; localNdx < workGroupSize; localNdx++)
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				*(deUint32*)((deUint8*)inputs + stride*(groupOffset+localNdx)) = rnd.getBool() ? ~0u : 0u;
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		workGroupSize	= (int)product(m_workGroupSize);
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numWorkGroups	= numValues/workGroupSize;
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numBits			= m_precision == PRECISION_HIGHP ? 32 :
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										  m_precision == PRECISION_MEDIUMP ? 16 : 8;
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	compareMask		= numBits == 32 ? ~0u : (1u<<numBits)-1u;
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		groupOffset		= groupNdx*workGroupSize;
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	groupOutput		= *(const deUint32*)((const deUint8*)groupOutputs + groupNdx*groupStride);
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	randomValue		= *(const int*)((const deUint8*)inputs + inputStride*groupOffset);
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	expected0		= randomValue ^ 0u;
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	expected1		= randomValue ^ ~0u;
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int				numXorZeros		= (m_initialValue == 0) ? 1 : 0;
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 1; localNdx < workGroupSize; localNdx++)
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 inputValue = *(const deUint32*)((const deUint8*)inputs + inputStride*(groupOffset+localNdx));
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (inputValue == 0)
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					numXorZeros += 1;
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32 expected = (numXorZeros%2 == 0) ? expected0 : expected1;
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if ((groupOutput & compareMask) != (expected & compareMask))
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected " << tcu::toHex(expected0)
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   << " or " << tcu::toHex(expected1) << " (compare mask " << tcu::toHex(compareMask)
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   << "), got " << tcu::toHex(groupOutput) << TestLog::EndMessage;
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32 outputValue = *(const deUint32*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if ((outputValue&compareMask) != 0 &&
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					(outputValue&compareMask) != compareMask &&
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					(outputValue&compareMask) != (expected0&compareMask) &&
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					(outputValue&compareMask) != (expected1&compareMask))
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << tcu::toHex(outputValue)
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicExchangeCase : public ShaderAtomicOpCase
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicExchangeCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: ShaderAtomicOpCase(context, name, "atomicExchange", operandType, type, precision, UVec3(3,2,1))
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_initialValue = 0;
8043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
8073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputs (int numValues, int stride, void* inputs) const
8083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
8103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int groupOffset = groupNdx*workGroupSize;
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				*(int*)((deUint8*)inputs + stride*(groupOffset+localNdx)) = localNdx+1;
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool verify (int numValues, int inputStride, const void* inputs, int outputStride, const void* outputs, int groupStride, const void* groupOutputs) const
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	workGroupSize	= (int)product(m_workGroupSize);
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numWorkGroups	= numValues/workGroupSize;
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_UNREF(inputStride && inputs);
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOffset		= groupNdx*workGroupSize;
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOutput		= *(const int*)((const deUint8*)groupOutputs + groupNdx*groupStride);
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			set<int>	usedValues;
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int outputValue = *(const int*)((const deUint8*)outputs + outputStride*(groupOffset+localNdx));
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!de::inRange(outputValue, 0, workGroupSize) || usedValues.find(outputValue) != usedValues.end())
8393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": found unexpected value " << outputValue
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				usedValues.insert(outputValue);
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (!de::inRange(groupOutput, 0, workGroupSize) || usedValues.find(groupOutput) != usedValues.end())
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": unexpected final value" << groupOutput << TestLog::EndMessage;
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ShaderAtomicCompSwapCase : public TestCase
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									ShaderAtomicCompSwapCase	(Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision);
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									~ShaderAtomicCompSwapCase	(void);
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void							init						(void);
8663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void							deinit						(void);
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult					iterate						(void);
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									ShaderAtomicCompSwapCase	(const ShaderAtomicCompSwapCase& other);
8733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicCompSwapCase&		operator=					(const ShaderAtomicCompSwapCase& other);
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperandType			m_operandType;
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const DataType					m_type;
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const Precision					m_precision;
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const UVec3						m_workGroupSize;
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const UVec3						m_numWorkGroups;
8813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderProgram*					m_program;
8833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
8843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8853c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicCompSwapCase::ShaderAtomicCompSwapCase (Context& context, const char* name, AtomicOperandType operandType, DataType type, Precision precision)
8863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCase			(context, name, "atomicCompSwap() Test")
8873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_operandType		(operandType)
8883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_type			(type)
8893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_precision		(precision)
8903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_workGroupSize	(3,2,1)
8913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_numWorkGroups	(4,4,4)
8923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_program			(DE_NULL)
8933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8963c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicCompSwapCase::~ShaderAtomicCompSwapCase (void)
8973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderAtomicCompSwapCase::deinit();
8993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9013c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderAtomicCompSwapCase::init (void)
9023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			isSSBO		= m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE;
9043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			precName	= getPrecisionName(m_precision);
9053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			typeName	= getDataTypeName(m_type);
9063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32		numValues	= product(m_workGroupSize)*product(m_numWorkGroups);
9073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
9083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "#version 310 es\n"
9103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "layout(local_size_x = " << m_workGroupSize.x()
9113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< ", local_size_y = " << m_workGroupSize.y()
9123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< ", local_size_z = " << m_workGroupSize.z() << ") in;\n"
9133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "layout(binding = 0) buffer InOut\n"
9143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
9153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " compareValues[" << numValues << "];\n"
9163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " exchangeValues[" << numValues << "];\n"
9173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " outputValues[" << numValues << "];\n"
9183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << (isSSBO ? "coherent " : "") << precName << " " << typeName << " groupValues[" << product(m_numWorkGroups) << "];\n"
9193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "} sb_inout;\n";
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!isSSBO)
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "shared " << precName << " " << typeName << " s_var;\n";
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n"
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "void main (void)\n"
9263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint localSize  = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n"
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint globalNdx  = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
9293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint globalOffs = localSize*globalNdx;\n"
9303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint offset     = globalOffs + gl_LocalInvocationIndex;\n"
9313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n";
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!isSSBO)
9343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "	if (gl_LocalInvocationIndex == 0u)\n"
9363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "		s_var = " << typeName << "(" << 0 << ");\n"
9373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "\n";
9383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "	" << precName << " " << typeName << " compare = sb_inout.compareValues[offset];\n"
9413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " exchange = sb_inout.exchangeValues[offset];\n"
9423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	" << precName << " " << typeName << " result;\n"
9438852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "	bool swapDone = false;\n"
9443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n"
9453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	for (uint ndx = 0u; ndx < localSize; ndx++)\n"
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	{\n"
9478852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "		barrier();\n"
9488852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "		if (!swapDone)\n"
9498852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "		{\n"
9508852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "			result = atomicCompSwap(" << (isSSBO ? "sb_inout.groupValues[globalNdx]" : "s_var") << ", compare, exchange);\n"
9518852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "			if (result == compare)\n"
9528852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "				swapDone = true;\n"
9538852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		<< "		}\n"
9543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	}\n"
9553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n"
9563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	sb_inout.outputValues[offset] = result;\n";
9573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!isSSBO)
9593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9608852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		src << "	barrier();\n"
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "	if (gl_LocalInvocationIndex == 0u)\n"
9623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "		sb_inout.groupValues[globalNdx] = s_var;\n";
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!m_program);
9683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_program = new ShaderProgram(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str()));
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_testCtx.getLog() << *m_program;
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_program->isOk())
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		delete m_program;
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_program = DE_NULL;
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::TestError("Compile failed");
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderAtomicCompSwapCase::deinit (void)
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	delete m_program;
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_program = DE_NULL;
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9863c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpCase::IterateResult ShaderAtomicCompSwapCase::iterate (void)
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				program			= m_program->getProgram();
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const Buffer				inoutBuffer		(m_context.getRenderContext());
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				blockNdx		= gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "InOut");
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceBlockInfo	blockInfo		= getProgramInterfaceBlockInfo(gl, program, GL_SHADER_STORAGE_BLOCK, blockNdx);
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				cmpVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.compareValues[0]");
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	cmpVarInfo		= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, cmpVarNdx);
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				exhVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.exchangeValues[0]");
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	exhVarInfo		= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, exhVarNdx);
9973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				outVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.outputValues[0]");
9983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	outVarInfo		= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, outVarNdx);
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				groupVarNdx		= gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.groupValues[0]");
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const InterfaceVariableInfo	groupVarInfo	= getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, groupVarNdx);
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				numValues		= product(m_workGroupSize)*product(m_numWorkGroups);
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(cmpVarInfo.arraySize == numValues &&
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  exhVarInfo.arraySize == numValues &&
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  outVarInfo.arraySize == numValues &&
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  groupVarInfo.arraySize == product(m_numWorkGroups));
10073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.useProgram(program);
10093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \todo [2013-09-05 pyry] Use randomized input values!
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup buffer.
10133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	workGroupSize	= product(m_workGroupSize);
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<deUint8>	bufData			(blockInfo.dataSize);
10163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::fill(bufData.begin(), bufData.end(), 0);
10183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (deUint32 ndx = 0; ndx < numValues; ndx++)
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(deUint32*)(&bufData[0] + cmpVarInfo.offset + cmpVarInfo.arrayStride*ndx) = ndx%workGroupSize;
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (deUint32 ndx = 0; ndx < numValues; ndx++)
10233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			*(deUint32*)(&bufData[0] + exhVarInfo.offset + exhVarInfo.arrayStride*ndx) = (ndx%workGroupSize)+1;
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inoutBuffer);
10263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockInfo.dataSize, &bufData[0], GL_STATIC_READ);
10273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *inoutBuffer);
10283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed");
10293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.dispatchCompute(m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
10323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back and compare
10343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const void*		resPtr			= gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, blockInfo.dataSize, GL_MAP_READ_BIT);
10363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		numWorkGroups	= (int)product(m_numWorkGroups);
10373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		workGroupSize	= (int)product(m_workGroupSize);
10383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool			isOk			= true;
10393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
10413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(resPtr);
10423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
10443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOffset		= groupNdx*workGroupSize;
10463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	groupOutput		= *(const int*)((const deUint8*)resPtr + groupVarInfo.offset + groupNdx*groupVarInfo.arrayStride);
10473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	refValue		= localNdx;
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	outputValue		= *(const int*)((const deUint8*)resPtr + outVarInfo.offset + outVarInfo.arrayStride*(groupOffset+localNdx));
10523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (outputValue != refValue)
10543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation " << localNdx
10563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << ": expected " << refValue << ", got " << outputValue
10573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
10583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					isOk = false;
10593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					break;
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (groupOutput != workGroupSize)
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected" << workGroupSize << ", got " << groupOutput << TestLog::EndMessage;
10663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				isOk = false;
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
10723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
10733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
10753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								isOk ? "Pass"				: "Comparison failed");
10763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return STOP;
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10813c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpTests::ShaderAtomicOpTests (Context& context, const char* name, AtomicOperandType operandType)
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCaseGroup	(context, name, "Atomic Operation Tests")
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_operandType	(operandType)
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10873c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderAtomicOpTests::~ShaderAtomicOpTests (void)
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T>
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic tcu::TestCaseGroup* createAtomicOpGroup (Context& context, AtomicOperandType operandType, const char* groupName)
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(context.getTestContext(), groupName, (string("Atomic ") + groupName).c_str());
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
10963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int precNdx = 0; precNdx < PRECISION_LAST; precNdx++)
10983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int typeNdx = 0; typeNdx < 2; typeNdx++)
11003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
11013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const Precision		precision		= Precision(precNdx);
11023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const DataType		type			= typeNdx > 0 ? TYPE_INT : TYPE_UINT;
11033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const string		caseName		= string(getPrecisionName(precision)) + "_" + getDataTypeName(type);
11043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				group->addChild(new T(context, caseName.c_str(), operandType, type, precision));
11063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
11073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return group;
11103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (...)
11123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		delete group;
11143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw;
11153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
11173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11183c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderAtomicOpTests::init (void)
11193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicAddCase>		(m_context, m_operandType, "add"));
11213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicMinCase>		(m_context, m_operandType, "min"));
11223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicMaxCase>		(m_context, m_operandType, "max"));
11233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicAndCase>		(m_context, m_operandType, "and"));
11243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicOrCase>		(m_context, m_operandType, "or"));
11253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicXorCase>		(m_context, m_operandType, "xor"));
11263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicExchangeCase>	(m_context, m_operandType, "exchange"));
11273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addChild(createAtomicOpGroup<ShaderAtomicCompSwapCase>	(m_context, m_operandType, "compswap"));
11283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
11293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // Functional
11313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // gles31
11323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // deqp
1133