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 Image Load & Store Tests.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "es31fShaderImageLoadStoreTests.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glsTextureTestUtil.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluContextInfo.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluRenderContext.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluShaderProgram.hpp"
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluObjectWrapper.hpp"
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluPixelTransfer.hpp"
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluTextureUtil.hpp"
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluStrUtil.hpp"
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluCallLogWrapper.hpp"
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluProgramInterfaceQuery.hpp"
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluDrawUtil.hpp"
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTestLog.hpp"
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTextureUtil.hpp"
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVector.hpp"
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuImageCompare.hpp"
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFloat.hpp"
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVectorUtil.hpp"
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deStringUtil.hpp"
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deSharedPtr.hpp"
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deUniquePtr.hpp"
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deRandom.hpp"
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMemory.h"
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwFunctions.hpp"
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwDefs.hpp"
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwEnums.hpp"
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <vector>
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <string>
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <algorithm>
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <map>
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing glu::RenderContext;
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::TestLog;
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec2;
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec3;
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec4;
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec2;
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec3;
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec4;
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::UVec2;
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::UVec3;
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::UVec4;
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::TextureFormat;
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::ConstPixelBufferAccess;
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::PixelBufferAccess;
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing de::toString;
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing de::SharedPtr;
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing de::UniquePtr;
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector;
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::string;
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace deqp
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace gls::TextureTestUtil;
81c4eb6f3271a0bcd54835e666e836e3e72beebbd2Peter Siketusing namespace glu::TextureTestUtil;
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace gles31
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace Functional
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Default image sizes used in most test cases.
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline IVec3 defaultImageSize (TextureType type)
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (type)
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_BUFFER:	return IVec3(64,	1,		1);
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D:		return IVec3(64,	64,		1);
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_CUBE:		return IVec3(64,	64,		1);
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_3D:		return IVec3(64,	64,		8);
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D_ARRAY:	return IVec3(64,	64,		8);
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return IVec3(-1);
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate <typename T, int Size>
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic string arrayStr (const T (&arr)[Size])
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	string result = "{ ";
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int i = 0; i < Size; i++)
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		result += (i > 0 ? ", " : "") + toString(arr[i]);
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	result += " }";
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return result;
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1148852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyrytemplate <typename T, int N>
1158852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyrystatic int arrayIndexOf (const T (&arr)[N], const T& e)
1168852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry{
1178852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	return (int)(std::find(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), e) - DE_ARRAY_BEGIN(arr));
1188852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry}
1198852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* getTextureTypeName (TextureType type)
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (type)
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_BUFFER:	return "buffer";
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D:		return "2d";
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_CUBE:		return "cube";
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_3D:		return "3d";
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D_ARRAY:	return "2d_array";
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return DE_NULL;
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatTypeUnsignedInteger (TextureFormat::ChannelType type)
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return type == TextureFormat::UNSIGNED_INT8		||
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::UNSIGNED_INT16	||
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::UNSIGNED_INT32;
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatTypeSignedInteger (TextureFormat::ChannelType type)
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return type == TextureFormat::SIGNED_INT8	||
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::SIGNED_INT16	||
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::SIGNED_INT32;
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatTypeInteger (TextureFormat::ChannelType type)
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return isFormatTypeUnsignedInteger(type) || isFormatTypeSignedInteger(type);
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatTypeUnorm (TextureFormat::ChannelType type)
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return type == TextureFormat::UNORM_INT8	||
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::UNORM_INT16	||
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::UNORM_INT32;
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatTypeSnorm (TextureFormat::ChannelType type)
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return type == TextureFormat::SNORM_INT8	||
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::SNORM_INT16	||
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   type == TextureFormat::SNORM_INT32;
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isFormatSupportedForTextureBuffer (const TextureFormat& format)
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (format.order)
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::RGB:
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return format.type == TextureFormat::FLOAT				||
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::SIGNED_INT32		||
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::UNSIGNED_INT32;
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Fallthroughs.
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::R:
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::RG:
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::RGBA:
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return format.type == TextureFormat::UNORM_INT8			||
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::HALF_FLOAT			||
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::FLOAT				||
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::SIGNED_INT8		||
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::SIGNED_INT16		||
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::SIGNED_INT32		||
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::UNSIGNED_INT8		||
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::UNSIGNED_INT16		||
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				   format.type == TextureFormat::UNSIGNED_INT32;
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline string getShaderImageFormatQualifier (const TextureFormat& format)
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char* orderPart;
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char* typePart;
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (format.order)
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::R:		orderPart = "r";		break;
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::RGBA:	orderPart = "rgba";		break;
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			orderPart = DE_NULL;
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (format.type)
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::FLOAT:				typePart = "32f";			break;
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::HALF_FLOAT:			typePart = "16f";			break;
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::UNSIGNED_INT32:		typePart = "32ui";			break;
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::UNSIGNED_INT16:		typePart = "16ui";			break;
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::UNSIGNED_INT8:		typePart = "8ui";			break;
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::SIGNED_INT32:		typePart = "32i";			break;
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::SIGNED_INT16:		typePart = "16i";			break;
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::SIGNED_INT8:		typePart = "8i";			break;
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::UNORM_INT16:		typePart = "16";			break;
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::UNORM_INT8:			typePart = "8";				break;
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::SNORM_INT16:		typePart = "16_snorm";		break;
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TextureFormat::SNORM_INT8:			typePart = "8_snorm";		break;
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			typePart = DE_NULL;
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return string() + orderPart + typePart;
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline string getShaderSamplerOrImageType (TextureFormat::ChannelType formatType, TextureType textureType, bool isSampler)
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char* const formatPart		= isFormatTypeUnsignedInteger(formatType)	? "u"
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: isFormatTypeSignedInteger(formatType)		? "i"
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: "";
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char* const imageTypePart		= textureType == TEXTURETYPE_BUFFER		? "Buffer"
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: textureType == TEXTURETYPE_2D			? "2D"
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: textureType == TEXTURETYPE_3D			? "3D"
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: textureType == TEXTURETYPE_CUBE		? "Cube"
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: textureType == TEXTURETYPE_2D_ARRAY	? "2DArray"
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: DE_NULL;
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return string() + formatPart + (isSampler ? "sampler" : "image") + imageTypePart;
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline string getShaderImageType (TextureFormat::ChannelType formatType, TextureType imageType)
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return getShaderSamplerOrImageType(formatType, imageType, false);
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline string getShaderSamplerType (TextureFormat::ChannelType formatType, TextureType imageType)
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return getShaderSamplerOrImageType(formatType, imageType, true);
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint32 getGLTextureTarget (TextureType texType)
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (texType)
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_BUFFER:	return GL_TEXTURE_BUFFER;
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D:		return GL_TEXTURE_2D;
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_3D:		return GL_TEXTURE_3D;
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_CUBE:		return GL_TEXTURE_CUBE_MAP;
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D_ARRAY:	return GL_TEXTURE_2D_ARRAY;
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return (deUint32)-1;
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic deUint32 cubeFaceToGLFace (tcu::CubeFace face)
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (face)
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case tcu::CUBEFACE_POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return GL_NONE;
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::Texture1D* newOneLevelTexture1D (const tcu::TextureFormat& format, int w)
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Texture1D* const res = new tcu::Texture1D(format, w);
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	res->allocLevel(0);
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::Texture2D* newOneLevelTexture2D (const tcu::TextureFormat& format, int w, int h)
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Texture2D* const res = new tcu::Texture2D(format, w, h);
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	res->allocLevel(0);
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::TextureCube* newOneLevelTextureCube (const tcu::TextureFormat& format, int size)
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureCube* const res = new tcu::TextureCube(format, size);
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		res->allocLevel((tcu::CubeFace)i, 0);
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::Texture3D* newOneLevelTexture3D (const tcu::TextureFormat& format, int w, int h, int d)
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Texture3D* const res = new tcu::Texture3D(format, w, h, d);
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	res->allocLevel(0);
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::Texture2DArray* newOneLevelTexture2DArray (const tcu::TextureFormat& format, int w, int h, int d)
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Texture2DArray* const res = new tcu::Texture2DArray(format, w, h, d);
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	res->allocLevel(0);
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline TextureType textureLayerType (TextureType entireTextureType)
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (entireTextureType)
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Single-layer types.
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Fallthrough.
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_BUFFER:
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D:
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return entireTextureType;
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Multi-layer types with 2d layers.
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_3D:
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_CUBE:
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D_ARRAY:
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return TEXTURETYPE_2D;
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return TEXTURETYPE_LAST;
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* const s_texBufExtString = "GL_EXT_texture_buffer";
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
354a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppestatic inline void checkTextureTypeExtensions (const glu::ContextInfo& contextInfo, TextureType type, const RenderContext& renderContext)
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
356a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	if (type == TEXTURETYPE_BUFFER && !contextInfo.isExtensionSupported(s_texBufExtString) && !glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)))
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::NotSupportedError("Test requires " + string(s_texBufExtString) + " extension");
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
360a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppestatic inline string textureTypeExtensionShaderRequires (TextureType type, const RenderContext& renderContext)
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
362a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)) && (type == TEXTURETYPE_BUFFER))
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return "#extension " + string(s_texBufExtString) + " : require\n";
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return "";
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
368a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppestatic const char* const s_imageAtomicExtString = "GL_OES_shader_image_atomic";
369a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe
370a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppestatic inline string imageAtomicExtensionShaderRequires (const RenderContext& renderContext)
371a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe{
372a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)))
373a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		return "#extension " + string(s_imageAtomicExtString) + " : require\n";
374a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	else
375a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		return "";
376a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe}
377a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyryenum AtomicOperation
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_ADD = 0,
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_MIN,
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_MAX,
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_AND,
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_OR,
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_XOR,
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_EXCHANGE,
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_COMP_SWAP,
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_LAST
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! An order-independent operation is one for which the end result doesn't depend on the order in which the operations are carried (i.e. is both commutative and associative).
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool isOrderIndependentAtomicOperation (AtomicOperation op)
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return op == ATOMIC_OPERATION_ADD	||
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   op == ATOMIC_OPERATION_MIN	||
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   op == ATOMIC_OPERATION_MAX	||
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   op == ATOMIC_OPERATION_AND	||
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   op == ATOMIC_OPERATION_OR	||
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		   op == ATOMIC_OPERATION_XOR;
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Computes the result of an atomic operation where "a" is the data operated on and "b" is the parameter to the atomic function.
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint computeBinaryAtomicOperationResult (AtomicOperation op, int a, int b)
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:			return a + b;
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:			return de::min(a, b);
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:			return de::max(a, b);
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:			return a & b;
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:			return a | b;
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:			return a ^ b;
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:		return b;
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return -1;
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! \note For floats, only the exchange operation is supported.
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat computeBinaryAtomicOperationResult (AtomicOperation op, float /*a*/, float b)
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE: return b;
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return -1;
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* getAtomicOperationCaseName (AtomicOperation op)
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:			return "add";
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:			return "min";
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:			return "max";
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:			return "and";
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:			return "or";
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:			return "xor";
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:		return "exchange";
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_COMP_SWAP:	return "comp_swap";
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return DE_NULL;
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* getAtomicOperationShaderFuncName (AtomicOperation op)
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:			return "imageAtomicAdd";
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:			return "imageAtomicMin";
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:			return "imageAtomicMax";
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:			return "imageAtomicAnd";
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:			return "imageAtomicOr";
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:			return "imageAtomicXor";
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:		return "imageAtomicExchange";
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_COMP_SWAP:	return "imageAtomicCompSwap";
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return DE_NULL;
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! In GLSL, when accessing cube images, the z coordinate is mapped to a cube face.
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! \note This is _not_ the same as casting the z to a tcu::CubeFace.
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline tcu::CubeFace glslImageFuncZToCubeFace (int z)
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const tcu::CubeFace faces[6] =
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_POSITIVE_X,
4793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_NEGATIVE_X,
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_POSITIVE_Y,
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_NEGATIVE_Y,
4823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_POSITIVE_Z,
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::CUBEFACE_NEGATIVE_Z
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(de::inBounds(z, 0, DE_LENGTH_OF_ARRAY(faces)));
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return faces[z];
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BufferMemMap
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	BufferMemMap (const glw::Functions& gl, deUint32 target, int offset, int size, deUint32 access)
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: m_gl		(gl)
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_target	(target)
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_ptr		(DE_NULL)
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_ptr = gl.mapBufferRange(target, offset, size, access);
4993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(m_ptr);
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	~BufferMemMap (void)
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_gl.unmapBuffer(m_target);
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*	getPtr		(void) const { return m_ptr; }
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*	operator*	(void) const { return m_ptr; }
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							BufferMemMap			(const BufferMemMap& other);
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	BufferMemMap&			operator=				(const BufferMemMap& other);
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	m_gl;
5163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			m_target;
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*					m_ptr;
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Utility for more readable uniform assignment logging; logs the name of the uniform when assigning. Handles the locations, querying them the first time they're assigned
5213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//  \note Assumes that the appropriate program is in use when assigning uniforms.
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass UniformAccessLogger
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	UniformAccessLogger (const glw::Functions& gl, TestLog& log, deUint32 programGL)
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: m_gl			(gl)
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_log			(log)
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_programGL	(programGL)
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						assign1i (const string& name, int x);
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						assign3f (const string& name, float x, float y, float z);
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int							getLocation (const string& name);
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&		m_gl;
5393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					m_log;
5403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				m_programGL;
5413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::map<string, int>		m_uniformLocations;
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint UniformAccessLogger::getLocation (const string& name)
5463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_uniformLocations.find(name) == m_uniformLocations.end())
5483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int loc = m_gl.getUniformLocation(m_programGL, name.c_str());
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(loc != -1);
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_uniformLocations[name] = loc;
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_uniformLocations[name];
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid UniformAccessLogger::assign1i (const string& name, int x)
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int loc = getLocation(name);
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << x << TestLog::EndMessage;
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_gl.uniform1i(loc, x);
5613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid UniformAccessLogger::assign3f (const string& name, float x, float y, float z)
5643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int loc = getLocation(name);
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << Vec3(x, y, z) << TestLog::EndMessage;
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_gl.uniform3f(loc, x, y, z);
5683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Class containing a (single-level) texture of a given type. Supports accessing pixels with coordinate convention similar to that in imageStore() and imageLoad() in shaders; useful especially for cube maps.
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass LayeredImage
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5733c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												LayeredImage				(TextureType type, const TextureFormat& format, int w, int h, int d);
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TextureType									getImageType				(void) const { return m_type; }
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&								getSize						(void) const { return m_size; }
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat&						getFormat					(void) const { return m_format; }
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \note For cube maps, set/getPixel's z parameter specifies the cube face in the same manner as in imageStore/imageLoad in GL shaders (see glslImageFuncZToCubeFace), instead of directly as a tcu::CubeFace.
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	template <typename ColorT>
5833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void										setPixel					(int x, int y, int z, const ColorT& color) const;
5843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	Vec4										getPixel					(int x, int y, int z) const;
5863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IVec4										getPixelInt					(int x, int y, int z) const;
5873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	UVec4										getPixelUint				(int x, int y, int z) const { return getPixelInt(x, y, z).asUint(); }
5883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getAccess					(void)							{ return getAccessInternal();				}
5903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getSliceAccess				(int slice)						{ return getSliceAccessInternal(slice);		}
5913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getCubeFaceAccess			(tcu::CubeFace face)			{ return getCubeFaceAccessInternal(face);	}
5923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ConstPixelBufferAccess						getAccess					(void)					const	{ return getAccessInternal();				}
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ConstPixelBufferAccess						getSliceAccess				(int slice)				const	{ return getSliceAccessInternal(slice);		}
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ConstPixelBufferAccess						getCubeFaceAccess			(tcu::CubeFace face)	const	{ return getCubeFaceAccessInternal(face);	}
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
5983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												LayeredImage				(const LayeredImage&);
5993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LayeredImage&								operator=					(const LayeredImage&);
6003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Some helpers to reduce code duplication between const/non-const versions of getAccess and others.
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getAccessInternal			(void) const;
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getSliceAccessInternal		(int slice) const;
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	PixelBufferAccess							getCubeFaceAccessInternal	(tcu::CubeFace face) const;
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType							m_type;
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3									m_size;
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat							m_format;
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \note Depending on m_type, exactly one of the following will contain non-null.
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const SharedPtr<tcu::Texture1D>				m_texBuffer;
6123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const SharedPtr<tcu::Texture2D>				m_tex2D;
6133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const SharedPtr<tcu::TextureCube>			m_texCube;
6143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const SharedPtr<tcu::Texture3D>				m_tex3D;
6153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const SharedPtr<tcu::Texture2DArray>		m_tex2DArray;
6163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6183c827367444ee418f129b2c238299f49d3264554Jarkko PoyryLayeredImage::LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d)
6193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_type		(type)
6203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_size		(w, h, d)
6213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_format		(format)
6223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_texBuffer	(type == TEXTURETYPE_BUFFER		? SharedPtr<tcu::Texture1D>			(newOneLevelTexture1D		(format, w))		: SharedPtr<tcu::Texture1D>())
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_tex2D		(type == TEXTURETYPE_2D			? SharedPtr<tcu::Texture2D>			(newOneLevelTexture2D		(format, w, h))		: SharedPtr<tcu::Texture2D>())
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_texCube		(type == TEXTURETYPE_CUBE		? SharedPtr<tcu::TextureCube>		(newOneLevelTextureCube		(format, w))		: SharedPtr<tcu::TextureCube>())
6253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_tex3D		(type == TEXTURETYPE_3D			? SharedPtr<tcu::Texture3D>			(newOneLevelTexture3D		(format, w, h, d))	: SharedPtr<tcu::Texture3D>())
6263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_tex2DArray	(type == TEXTURETYPE_2D_ARRAY	? SharedPtr<tcu::Texture2DArray>	(newOneLevelTexture2DArray	(format, w, h, d))	: SharedPtr<tcu::Texture2DArray>())
6273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_size.z() == 1					||
6293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_3D			||
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_2D_ARRAY);
6313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_size.y() == 1					||
6333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_2D			||
6343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_CUBE		||
6353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_3D			||
6363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_type == TEXTURETYPE_2D_ARRAY);
6373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(w == h || type != TEXTURETYPE_CUBE);
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_texBuffer	!= DE_NULL ||
6413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_tex2D		!= DE_NULL ||
6423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_texCube		!= DE_NULL ||
6433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_tex3D		!= DE_NULL ||
6443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  m_tex2DArray	!= DE_NULL);
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate <typename ColorT>
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid LayeredImage::setPixel (int x, int y, int z, const ColorT& color) const
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const PixelBufferAccess access = m_type == TEXTURETYPE_BUFFER		? m_texBuffer->getLevel(0)
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   : m_type == TEXTURETYPE_2D			? m_tex2D->getLevel(0)
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   : m_type == TEXTURETYPE_CUBE			? m_texCube->getLevelFace(0, glslImageFuncZToCubeFace(z))
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   : m_type == TEXTURETYPE_3D			? m_tex3D->getLevel(0)
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   : m_type == TEXTURETYPE_2D_ARRAY		? m_tex2DArray->getLevel(0)
655b5d323b0daefbf7f7f4cb5e9cc631e2ab837b6edPyry Haulos								   : PixelBufferAccess();
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	access.setPixel(color, x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6603c827367444ee418f129b2c238299f49d3264554Jarkko PoyryVec4 LayeredImage::getPixel (int x, int y, int z) const
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return access.getPixel(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6663c827367444ee418f129b2c238299f49d3264554Jarkko PoyryIVec4 LayeredImage::getPixelInt (int x, int y, int z) const
6673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return access.getPixelInt(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6723c827367444ee418f129b2c238299f49d3264554Jarkko PoyryPixelBufferAccess LayeredImage::getAccessInternal (void) const
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_type == TEXTURETYPE_BUFFER || m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_3D || m_type == TEXTURETYPE_2D_ARRAY);
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_type == TEXTURETYPE_BUFFER		? m_texBuffer->getLevel(0)
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		 : m_type == TEXTURETYPE_2D			? m_tex2D->getLevel(0)
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		 : m_type == TEXTURETYPE_3D			? m_tex3D->getLevel(0)
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		 : m_type == TEXTURETYPE_2D_ARRAY	? m_tex2DArray->getLevel(0)
680b5d323b0daefbf7f7f4cb5e9cc631e2ab837b6edPyry Haulos		 : PixelBufferAccess();
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6833c827367444ee418f129b2c238299f49d3264554Jarkko PoyryPixelBufferAccess LayeredImage::getSliceAccessInternal (int slice) const
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const PixelBufferAccess srcAccess = getAccessInternal();
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::getSubregion(srcAccess, 0, 0, slice, srcAccess.getWidth(), srcAccess.getHeight(), 1);
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6893c827367444ee418f129b2c238299f49d3264554Jarkko PoyryPixelBufferAccess LayeredImage::getCubeFaceAccessInternal (tcu::CubeFace face) const
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_type == TEXTURETYPE_CUBE);
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_texCube->getLevelFace(0, face);
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Set texture storage or, if using buffer texture, setup buffer and attach to texture.
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void setTextureStorage (glu::CallLogWrapper& glLog, TextureType imageType, deUint32 internalFormat, const IVec3& imageSize, deUint32 textureBufGL)
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32 textureTarget = getGLTextureTarget(imageType);
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (imageType)
7013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_BUFFER:
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const TextureFormat		format		= glu::mapGLInternalFormat(internalFormat);
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				numBytes	= format.getPixelSize() * imageSize.x();
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(isFormatSupportedForTextureBuffer(format));
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL);
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBufferData(GL_TEXTURE_BUFFER, numBytes, DE_NULL, GL_STATIC_DRAW);
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, textureBufGL);
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(imageSize.y() == 1 && imageSize.z() == 1);
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Fall-throughs.
7153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D:
7173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_CUBE:
7183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glTexStorage2D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y());
7193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(imageSize.z() == 1);
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_3D:
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case TEXTURETYPE_2D_ARRAY:
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glTexStorage3D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y(), imageSize.z());
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void uploadTexture (glu::CallLogWrapper& glLog, const LayeredImage& src, deUint32 textureBufGL)
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormat	= glu::getInternalFormat(src.getFormat());
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::TransferFormat	transferFormat	= glu::getTransferFormat(src.getFormat());
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize		= src.getSize();
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, src.getImageType(), internalFormat, imageSize, textureBufGL);
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	pixelSize = src.getFormat().getPixelSize();
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int			unpackAlignment;
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (deIsPowerOfTwo32(pixelSize))
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			unpackAlignment = 8;
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			unpackAlignment = 1;
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment);
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (src.getImageType() == TEXTURETYPE_BUFFER)
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL);
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBufferData(GL_TEXTURE_BUFFER, src.getFormat().getPixelSize() * imageSize.x(), src.getAccess().getDataPtr(), GL_STATIC_DRAW);
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (src.getImageType() == TEXTURETYPE_2D)
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr());
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (src.getImageType() == TEXTURETYPE_CUBE)
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::CubeFace face = (tcu::CubeFace)faceI;
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glTexSubImage2D(cubeFaceToGLFace(face), 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getCubeFaceAccess(face).getDataPtr());
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(src.getImageType() == TEXTURETYPE_3D || src.getImageType() == TEXTURETYPE_2D_ARRAY);
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32 textureTarget = getGLTextureTarget(src.getImageType());
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glTexSubImage3D(textureTarget, 0, 0, 0, 0, imageSize.x(), imageSize.y(), imageSize.z(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr());
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void readPixelsRGBAInteger32 (const PixelBufferAccess& dst, int originX, int originY, glu::CallLogWrapper& glLog)
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(dst.getDepth() == 1);
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (isFormatTypeUnsignedInteger(dst.getFormat().type))
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<UVec4> data(dst.getWidth()*dst.getHeight());
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < dst.getHeight(); y++)
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < dst.getWidth(); x++)
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			dst.setPixel(data[y*dst.getWidth() + x], x, y);
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (isFormatTypeSignedInteger(dst.getFormat().type))
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<IVec4> data(dst.getWidth()*dst.getHeight());
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < dst.getHeight(); y++)
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < dst.getWidth(); x++)
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			dst.setPixel(data[y*dst.getWidth() + x], x, y);
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(false);
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Base for a functor for verifying and logging a 2d texture layer (2d image, cube face, 3d slice, 2d layer).
8043c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ImageLayerVerifier
8053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
8073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual bool	operator()				(TestLog&, const ConstPixelBufferAccess&, int sliceOrFaceNdx) const = 0;
8083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual			~ImageLayerVerifier		(void) {}
8093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
8103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void setTexParameteri (glu::CallLogWrapper& glLog, deUint32 target)
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (target != GL_TEXTURE_BUFFER)
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Binds texture (one layer at a time) to color attachment of FBO and does glReadPixels(). Calls the verifier for each layer.
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! \note Not for buffer textures.
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool readIntegerTextureViaFBOAndVerify (const RenderContext&			renderCtx,
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   glu::CallLogWrapper&			glLog,
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   deUint32						textureGL,
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   TextureType					textureType,
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   const TextureFormat&			textureFormat,
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   const IVec3&					textureSize,
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											   const ImageLayerVerifier&	verifyLayer)
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(isFormatTypeInteger(textureFormat.type));
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog& log = glLog.getLog();
8343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::ScopedLogSection section(log, "Verification", "Result verification (bind texture layer-by-layer to FBO, read with glReadPixels())");
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			numSlicesOrFaces	= textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z();
8383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32		textureTargetGL		= getGLTextureTarget(textureType);
8393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::Framebuffer	fbo					(renderCtx);
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureLevel	resultSlice			(textureFormat, textureSize.x(), textureSize.y());
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind FBO");
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glMemoryBarrier");
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, textureGL);
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (textureType == TEXTURETYPE_CUBE)
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)), textureGL, 0);
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (textureType == TEXTURETYPE_2D)
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureGL, 0);
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (textureType == TEXTURETYPE_3D || textureType == TEXTURETYPE_2D_ARRAY)
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureGL, 0, sliceOrFaceNdx);
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind texture to framebuffer color attachment 0");
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
8663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		readPixelsRGBAInteger32(resultSlice.getAccess(), 0, 0, glLog);
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glReadPixels");
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!verifyLayer(log, resultSlice, sliceOrFaceNdx))
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return true;
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Reads texture with texture() in compute shader, one layer at a time, putting values into a SSBO and reading with a mapping. Calls the verifier for each layer.
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! \note Not for buffer textures.
8793c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool readFloatOrNormTextureWithLookupsAndVerify (const RenderContext&		renderCtx,
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														glu::CallLogWrapper&		glLog,
8813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														deUint32					textureGL,
8823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														TextureType					textureType,
8833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														const TextureFormat&		textureFormat,
8843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														const IVec3&				textureSize,
8853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														const ImageLayerVerifier&	verifyLayer)
8863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!isFormatTypeInteger(textureFormat.type));
8883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
8893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog& log = glLog.getLog();
8913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::ScopedLogSection section(log, "Verification", "Result verification (read texture layer-by-layer in compute shader with texture() into SSBO)");
893a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	const std::string			glslVersionDeclaration = getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
8943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::ShaderProgram program(renderCtx,
896a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
8973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
8983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"layout (binding = 0) buffer Output\n"
8993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"{\n"
9003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	vec4 color[" + toString(textureSize.x()*textureSize.y()) + "];\n"
9013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"} sb_out;\n"
9023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"\n"
9033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"precision highp " + getShaderSamplerType(textureFormat.type, textureType) + ";\n"
9043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"\n"
9053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"uniform highp " + getShaderSamplerType(textureFormat.type, textureType) + " u_texture;\n"
9063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"uniform highp vec3 u_texCoordLD;\n"
9073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"uniform highp vec3 u_texCoordRD;\n"
9083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"uniform highp vec3 u_texCoordLU;\n"
9093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"uniform highp vec3 u_texCoordRU;\n"
9103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"\n"
9113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"void main (void)\n"
9123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"{\n"
9133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	int gx = int(gl_GlobalInvocationID.x);\n"
9143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	int gy = int(gl_GlobalInvocationID.y);\n"
9153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	highp float s = (float(gx) + 0.5) / float(" + toString(textureSize.x()) + ");\n"
9163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	highp float t = (float(gy) + 0.5) / float(" + toString(textureType == TEXTURETYPE_CUBE ? textureSize.x() : textureSize.y()) + ");\n"
9173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	highp vec3 texCoord = u_texCoordLD*(1.0-s)*(1.0-t)\n"
9183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	                    + u_texCoordRD*(    s)*(1.0-t)\n"
9193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	                    + u_texCoordLU*(1.0-s)*(    t)\n"
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	                    + u_texCoordRU*(    s)*(    t);\n"
9213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	int ndx = gy*" + toString(textureSize.x()) + " + gx;\n"
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"	sb_out.color[ndx] = texture(u_texture, texCoord" + (textureType == TEXTURETYPE_2D ? ".xy" : "") + ");\n"
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													"}\n"));
9243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glUseProgram(program.getProgram());
9263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << program;
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!program.isOk())
9303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Failure: failed to compile program" << TestLog::EndMessage;
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_FAIL("Program compilation failed");
9333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32			textureTargetGL		= getGLTextureTarget(textureType);
9373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Buffer		outputBuffer		(renderCtx);
9383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger		uniforms			(renderCtx.getFunctions(), log, program.getProgram());
9393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup texture.
9413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glActiveTexture(GL_TEXTURE0);
9433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindTexture(textureTargetGL, textureGL);
9443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTexParameteri(glLog, textureTargetGL);
9453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		uniforms.assign1i("u_texture", 0);
9473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup output buffer.
9493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32		blockIndex		= glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output");
9513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			blockSize		= glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE);
9523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << TestLog::Message << "// Got buffer data size = " << blockSize << TestLog::EndMessage;
9543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TCU_CHECK(blockSize > 0);
9553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer);
9573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ);
9583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer);
9593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "SSB setup failed");
9603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Dispatch one layer at a time, read back and verify.
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int							numSlicesOrFaces	= textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z();
9653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::TextureLevel					resultSlice			(textureFormat, textureSize.x(), textureSize.y());
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const PixelBufferAccess				resultSliceAccess	= resultSlice.getAccess();
9673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32						blockIndex			= glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output");
9683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int							blockSize			= glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE);
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32						valueIndex			= glLog.glGetProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.color");
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::InterfaceVariableInfo	valueInfo			= glu::getProgramInterfaceVariableInfo(renderCtx.getFunctions(), program.getProgram(), GL_BUFFER_VARIABLE, valueIndex);
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TCU_CHECK(valueInfo.arraySize == (deUint32)(textureSize.x()*textureSize.y()));
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (textureType == TEXTURETYPE_CUBE)
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					vector<float> coords;
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					computeQuadTexCoordCube(coords, glslImageFuncZToCubeFace(sliceOrFaceNdx));
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordLD", coords[3*0 + 0], coords[3*0 + 1], coords[3*0 + 2]);
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordRD", coords[3*2 + 0], coords[3*2 + 1], coords[3*2 + 2]);
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordLU", coords[3*1 + 0], coords[3*1 + 1], coords[3*1 + 2]);
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordRU", coords[3*3 + 0], coords[3*3 + 1], coords[3*3 + 2]);
9863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float z = textureType == TEXTURETYPE_3D ?
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										((float)sliceOrFaceNdx + 0.5f) / (float)numSlicesOrFaces :
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										(float)sliceOrFaceNdx;
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordLD", 0.0f, 0.0f, z);
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordRD", 1.0f, 0.0f, z);
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordLU", 0.0f, 1.0f, z);
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uniforms.assign3f("u_texCoordRU", 1.0f, 1.0f, z);
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glDispatchCompute(textureSize.x(), textureSize.y(), 1);
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Note: mapping buffer and reading color values written" << TestLog::EndMessage;
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const BufferMemMap bufMap(renderCtx.getFunctions(), GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT);
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int y = 0; y < textureSize.y(); y++)
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int x = 0; x < textureSize.x(); x++)
10073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const int				ndx			= y*textureSize.x() + x;
10093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const float* const		clrData		= (const float*)((const deUint8*)bufMap.getPtr() + valueInfo.offset + valueInfo.arrayStride*ndx);
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						switch (textureFormat.order)
10123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
10133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							case TextureFormat::R:		resultSliceAccess.setPixel(Vec4(clrData[0]),											x, y); break;
10143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							case TextureFormat::RGBA:	resultSliceAccess.setPixel(Vec4(clrData[0], clrData[1], clrData[2], clrData[3]),		x, y); break;
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							default:
10163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								DE_ASSERT(false);
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
10183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!verifyLayer(log, resultSliceAccess, sliceOrFaceNdx))
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
10233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
10273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Read buffer texture by reading the corresponding buffer with a mapping.
10313c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool readBufferTextureWithMappingAndVerify (const RenderContext&			renderCtx,
10323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   glu::CallLogWrapper&			glLog,
10333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   deUint32						bufferGL,
10343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   const TextureFormat&			textureFormat,
10353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   int							imageSize,
10363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   const ImageLayerVerifier&	verifyLayer)
10373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureLevel			result			(textureFormat, imageSize, 1);
10393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const PixelBufferAccess		resultAccess	= result.getAccess();
1040a4a7880d032d3acbdd3f454886ccbce9e967eca5Jarkko Pöyry	const int					dataSize		= imageSize * textureFormat.getPixelSize();
10413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::ScopedLogSection section(glLog.getLog(), "Verification", "Result verification (read texture's buffer with a mapping)");
10433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindBuffer(GL_TEXTURE_BUFFER, bufferGL);
10443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1046a4a7880d032d3acbdd3f454886ccbce9e967eca5Jarkko Pöyry		const BufferMemMap bufMap(renderCtx.getFunctions(), GL_TEXTURE_BUFFER, 0, dataSize, GL_MAP_READ_BIT);
1047a4a7880d032d3acbdd3f454886ccbce9e967eca5Jarkko Pöyry		deMemcpy(resultAccess.getDataPtr(), bufMap.getPtr(), dataSize);
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyLayer(glLog.getLog(), resultAccess, 0);
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Calls the appropriate texture verification function depending on texture format or type.
10543c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool readTextureAndVerify (const RenderContext&			renderCtx,
10553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  glu::CallLogWrapper&			glLog,
10563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  deUint32						textureGL,
10573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  deUint32						bufferGL,
10583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  TextureType					textureType,
10593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  const TextureFormat&			textureFormat,
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  const IVec3&					imageSize,
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								  const ImageLayerVerifier&		verifyLayer)
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (textureType == TEXTURETYPE_BUFFER)
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return readBufferTextureWithMappingAndVerify(renderCtx, glLog, bufferGL, textureFormat, imageSize.x(), verifyLayer);
10653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
10663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return isFormatTypeInteger(textureFormat.type) ? readIntegerTextureViaFBOAndVerify				(renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer)
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   : readFloatOrNormTextureWithLookupsAndVerify		(renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer);
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! An ImageLayerVerifier that simply compares the result slice to a slice in a reference image.
10713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! \note Holds the reference image as a reference (no pun intended) instead of a copy; caller must be aware of lifetime issues.
10723c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ImageLayerComparer : public ImageLayerVerifier
10733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
10753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ImageLayerComparer (const LayeredImage& reference,
10763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const IVec2& relevantRegion = IVec2(0) /* If given, only check this region of each slice. */)
10773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: m_reference		(reference)
10783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_relevantRegion	(relevantRegion.x() > 0 && relevantRegion.y() > 0 ? relevantRegion : reference.getSize().swizzle(0, 1))
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const tcu::ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool						isCube				= m_reference.getImageType() == TEXTURETYPE_CUBE;
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const ConstPixelBufferAccess	referenceSlice		= tcu::getSubregion(isCube ? m_reference.getCubeFaceAccess(glslImageFuncZToCubeFace(sliceOrFaceNdx))
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																					   : m_reference.getSliceAccess(sliceOrFaceNdx),
10873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																				0, 0, m_relevantRegion.x(), m_relevantRegion.y());
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string comparisonName = "Comparison" + toString(sliceOrFaceNdx);
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string comparisonDesc = "Image Comparison, "
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									+ (isCube ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											  : "slice " + toString(sliceOrFaceNdx));
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (isFormatTypeInteger(m_reference.getFormat().type))
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, UVec4(0), tcu::COMPARE_LOG_RESULT);
10963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
10973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
10983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11003c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
11013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const LayeredImage&		m_reference;
11023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec2				m_relevantRegion;
11033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
11043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Case that just stores some computation results into an image.
11063c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ImageStoreCase : public TestCase
11073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11083c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
11093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum CaseFlag
11103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CASEFLAG_SINGLE_LAYER_BIND = 1 << 0 //!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched.
11123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
11133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ImageStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0)
11153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase				(context, name, description)
11163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_format				(format)
11173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_textureType			(textureType)
11183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0)
11193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1122a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
11233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult	iterate		(void);
11243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11253c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
11263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat		m_format;
11273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType		m_textureType;
11283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool				m_singleLayerBind;
11293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
11303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11313c827367444ee418f129b2c238299f49d3264554Jarkko PoyryImageStoreCase::IterateResult ImageStoreCase::iterate (void)
11323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx				= m_context.getRenderContext();
11343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log						(m_testCtx.getLog());
11353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
11363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
11373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL			= getGLTextureTarget(m_textureType);
11383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize				= defaultImageSize(m_textureType);
11393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					numSlicesOrFaces		= m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
11403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					maxImageDimension		= de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z()));
11413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float					storeColorScale			= isFormatTypeUnorm(m_format.type) ? 1.0f / (float)(maxImageDimension - 1)
11423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														: isFormatTypeSnorm(m_format.type) ? 2.0f / (float)(maxImageDimension - 1)
11433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														: 1.0f;
11443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float					storeColorBias			= isFormatTypeSnorm(m_format.type) ? -1.0f : 0.0f;
11453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			textureBuf				(renderCtx); // \note Only really used if using buffer texture.
11463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			texture					(renderCtx);
11473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
11493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup texture.
11513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
11533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_textureType == TEXTURETYPE_BUFFER)
11543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage;
11553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
11573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, *texture);
11583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
11593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, m_textureType, internalFormatGL, imageSize, *textureBuf);
11603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform image stores in compute shader.
11623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
11653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
11673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const TextureType	shaderImageType			= m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType;
11683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, shaderImageType);
11693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool			isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
11703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool			isIntFormat				= isFormatTypeSignedInteger(m_format.type);
11713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		colorBaseExpr			= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4(gx^gy^gz, "
11723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																												 "(" + toString(imageSize.x()-1) + "-gx)^gy^gz, "
11733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																												 "gx^(" + toString(imageSize.y()-1) + "-gy)^gz, "
11743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																												 "(" + toString(imageSize.x()-1) + "-gx)^(" + toString(imageSize.y()-1) + "-gy)^gz)";
11753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		colorExpr				= colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + toString(storeColorScale))
11763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	+ (storeColorBias == 0.0f ? "" : " + float(" + toString(storeColorBias) + ")");
1177a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const std::string	glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
11783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
1180a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1181a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
11823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
11833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
11843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
11853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
11863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) writeonly uniform " + shaderImageTypeStr + " u_image;\n"
11873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_singleLayerBind ? "uniform int u_layerNdx;\n" : "") +
11883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
11893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
11903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
11913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gx = int(gl_GlobalInvocationID.x);\n"
11923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gy = int(gl_GlobalInvocationID.y);\n"
11933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gz = " + (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") + ";\n"
11943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (shaderImageType == TEXTURETYPE_BUFFER ?
11953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_image, gx, " + colorExpr + ");\n"
11963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : shaderImageType == TEXTURETYPE_2D ?
11973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_image, ivec2(gx, gy), " + colorExpr + ");\n"
11983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ?
11993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_image, ivec3(gx, gy, gz), " + colorExpr + ");\n"
12003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : DE_NULL) +
12013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
12023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
12043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
12063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
12083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
12103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
12113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
12143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
12163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_singleLayerBind)
12183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
12203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
12213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (layerNdx > 0)
12223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
12233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				uniforms.assign1i("u_layerNdx", layerNdx);
12253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glBindImageTexture(0, *texture, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, internalFormatGL);
12273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
12283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
12303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
12313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
12323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
12343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
12363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
12373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
12393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
12403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Create reference, read texture and compare to reference.
12443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		isIntegerFormat		= isFormatTypeInteger(m_format.type);
12463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		LayeredImage	reference			(m_textureType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
12473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(!isIntegerFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
12493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int z = 0; z < numSlicesOrFaces; z++)
12513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < imageSize.y(); y++)
12523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < imageSize.x(); x++)
12533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z);
12553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (isIntegerFormat)
12573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(x, y, z, color);
12583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
12593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
12603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_textureType, m_format, imageSize, ImageLayerComparer(reference));
12633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
12653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
12663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Case that copies an image to another, using imageLoad() and imageStore(). Texture formats don't necessarily match image formats.
12703c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ImageLoadAndStoreCase : public TestCase
12713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12723c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
12733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum CaseFlag
12743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CASEFLAG_SINGLE_LAYER_BIND	= 1 << 0,	//!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched.
12763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CASEFLAG_RESTRICT_IMAGES	= 1 << 1	//!< If given, images in shader will be qualified with "restrict".
12773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
12783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0)
12803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase				(context, name, description)
12813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_textureFormat		(format)
12823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageFormat			(format)
12833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_textureType			(textureType)
12843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_restrictImages		((caseFlags & CASEFLAG_RESTRICT_IMAGES)		!= 0)
12853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND)	!= 0)
12863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& textureFormat, const TextureFormat& imageFormat, TextureType textureType, deUint32 caseFlags = 0)
12903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase				(context, name, description)
12913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_textureFormat		(textureFormat)
12923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageFormat			(imageFormat)
12933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_textureType			(textureType)
12943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_restrictImages		((caseFlags & CASEFLAG_RESTRICT_IMAGES)		!= 0)
12953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND)	!= 0)
12963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(textureFormat.getPixelSize() == imageFormat.getPixelSize());
12983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1300a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
13013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult	iterate		(void);
13023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13033c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
13043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatStorageType>
13053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void					replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat);
13063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat			m_textureFormat;
13083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat			m_imageFormat;
13093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType			m_textureType;
13103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					m_restrictImages;
13113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					m_singleLayerBind;
13123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
13133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13143c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatTypeStorageType>
13153c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ImageLoadAndStoreCase::replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat)
13163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Find potential bad values, such as nan or inf, and replace with something else.
13183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		pixelSize			= imageFormat.getPixelSize();
13193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		imageNumChannels	= imageFormat.order == tcu::TextureFormat::R	? 1
13203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: imageFormat.order == tcu::TextureFormat::RGBA	? 4
13213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										: 0;
13223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3		imageSize			= image.getSize();
13233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		numSlicesOrFaces	= image.getImageType() == TEXTURETYPE_CUBE ? 6 : imageSize.z();
13243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(pixelSize % imageNumChannels == 0);
13263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int z = 0; z < numSlicesOrFaces; z++)
13283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
13293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const PixelBufferAccess		sliceAccess		= image.getImageType() == TEXTURETYPE_CUBE ? image.getCubeFaceAccess((tcu::CubeFace)z) : image.getSliceAccess(z);
13303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int					rowPitch		= sliceAccess.getRowPitch();
13313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		void *const					data			= sliceAccess.getDataPtr();
13323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < imageSize.y(); y++)
13343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < imageSize.x(); x++)
13353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
13373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int c = 0; c < imageNumChannels; c++)
13393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
13403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				void *const			channelData		= (deUint8*)pixelData + c*pixelSize/imageNumChannels;
13413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const TcuFloatType	f				(*(TcuFloatTypeStorageType*)channelData);
13423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (f.isDenorm() || f.isInf() || f.isNaN())
13443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					*(TcuFloatTypeStorageType*)channelData = TcuFloatType(0.0f).bits();
13453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
13483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
13493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13503c827367444ee418f129b2c238299f49d3264554Jarkko PoyryImageLoadAndStoreCase::IterateResult ImageLoadAndStoreCase::iterate (void)
13513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx					= m_context.getRenderContext();
13533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log							(m_testCtx.getLog());
13543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog						(renderCtx.getFunctions(), log);
13553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureInternalFormatGL		= glu::getInternalFormat(m_textureFormat);
13563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				imageInternalFormatGL		= glu::getInternalFormat(m_imageFormat);
13573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL				= getGLTextureTarget(m_textureType);
13583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize					= defaultImageSize(m_textureType);
13593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					maxImageDimension			= de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z()));
13603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float					storeColorScale				= isFormatTypeUnorm(m_textureFormat.type) ? 1.0f / (float)(maxImageDimension - 1)
13613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: isFormatTypeSnorm(m_textureFormat.type) ? 2.0f / (float)(maxImageDimension - 1)
13623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: 1.0f;
13633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float					storeColorBias				= isFormatTypeSnorm(m_textureFormat.type) ? -1.0f : 0.0f;
13643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					numSlicesOrFaces			= m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
13653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isIntegerTextureFormat		= isFormatTypeInteger(m_textureFormat.type);
13663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			texture0Buf					(renderCtx);
13673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			texture1Buf					(renderCtx);
13683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			texture0					(renderCtx);
13693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			texture1					(renderCtx);
13703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LayeredImage				reference					(m_textureType, m_textureFormat, imageSize.x(), imageSize.y(), imageSize.z());
13713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
13733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup textures.
13753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created 2 textures (names " << *texture0 << " and " << *texture1 << ")" << TestLog::EndMessage;
13773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_textureType == TEXTURETYPE_BUFFER)
13783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created buffers for the textures (names " << *texture0Buf << " and " << *texture1Buf << ")" << TestLog::EndMessage;
13793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// First, fill reference with (a fairly arbitrary) initial pattern. This will be used as texture upload source data as well as for actual reference computation later on.
13813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!isIntegerTextureFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
13833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int z = 0; z < numSlicesOrFaces; z++)
13853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int y = 0; y < imageSize.y(); y++)
13863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int x = 0; x < imageSize.x(); x++)
13873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
13883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z);
13893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (isIntegerTextureFormat)
13913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			reference.setPixel(x, y, z, color);
13923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
13933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
13943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
13953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// If re-interpreting the texture contents as floating point values, need to get rid of inf, nan etc.
13973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_imageFormat.type == TextureFormat::HALF_FLOAT && m_textureFormat.type != TextureFormat::HALF_FLOAT)
13983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		replaceBadFloatReinterpretValues<TextureFormat::HALF_FLOAT, tcu::Float16, deUint16>(reference, m_imageFormat);
13993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (m_imageFormat.type == TextureFormat::FLOAT && m_textureFormat.type != TextureFormat::FLOAT)
14003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		replaceBadFloatReinterpretValues<TextureFormat::FLOAT, tcu::Float32, deUint32>(reference, m_imageFormat);
14013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Upload initial pattern to texture 0.
14033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
14053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, *texture0);
14063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
14073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Filling texture " << *texture0 << " with xor pattern" << TestLog::EndMessage;
14093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	uploadTexture(glLog, reference, *texture0Buf);
14113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Set storage for texture 1.
14133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE1);
14153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, *texture1);
14163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
14173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, m_textureType, textureInternalFormatGL, imageSize, *texture1Buf);
14183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform image loads and stores in compute shader and finalize reference computation.
14203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
14223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
14233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const char* const		maybeRestrict			= m_restrictImages ? "restrict" : "";
14253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string			shaderImageFormatStr	= getShaderImageFormatQualifier(m_imageFormat);
14263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const TextureType		shaderImageType			= m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType;
14273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string			shaderImageTypeStr		= getShaderImageType(m_imageFormat.type, shaderImageType);
1428a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const std::string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
14293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
1431a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1432a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
14333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
14343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
14353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
14363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
14373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) " + maybeRestrict + " readonly uniform " + shaderImageTypeStr + " u_image0;\n"
14383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=1) " + maybeRestrict + " writeonly uniform " + shaderImageTypeStr + " u_image1;\n"
14393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
14403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
14413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
14423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (shaderImageType == TEXTURETYPE_BUFFER ?
14433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	int pos = int(gl_GlobalInvocationID.x);\n"
14448852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry															"	imageStore(u_image1, pos, imageLoad(u_image0, " + toString(imageSize.x()-1) + "-pos));\n"
14453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : shaderImageType == TEXTURETYPE_2D ?
14463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
14473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + toString(imageSize.x()-1) + "-pos.x, pos.y)));\n"
14483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ?
14493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	ivec3 pos = ivec3(gl_GlobalInvocationID);\n"
14503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" + toString(imageSize.x()-1) + "-pos.x, pos.y, pos.z)));\n"
14513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : DE_NULL) +
14523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
14533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
14553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
14573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
14593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
14613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
14623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
14653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
14673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_singleLayerBind)
14693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
14713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
14723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (layerNdx > 0)
14733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
14743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glBindImageTexture(0, *texture0, 0, GL_FALSE, layerNdx, GL_READ_ONLY, imageInternalFormatGL);
14763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
14773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glBindImageTexture(1, *texture1, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, imageInternalFormatGL);
14793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
14803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
14823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
14833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
14843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
14863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindImageTexture(0, *texture0, 0, GL_TRUE, 0, GL_READ_ONLY, imageInternalFormatGL);
14883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
14893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glBindImageTexture(1, *texture1, 0, GL_TRUE, 0, GL_WRITE_ONLY, imageInternalFormatGL);
14913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
14923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
14943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
14953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Finalize reference.
14983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_textureFormat != m_imageFormat)
15003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Format re-interpretation case. Read data with image format and write back, with the same image format.
15023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// We do this because the data may change a little during lookups (e.g. unorm8 -> float; not all unorms can be exactly represented as floats).
15033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int					pixelSize		= m_imageFormat.getPixelSize();
15053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::TextureLevel			scratch			(m_imageFormat, 1, 1);
15063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const PixelBufferAccess		scratchAccess	= scratch.getAccess();
15073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int z = 0; z < numSlicesOrFaces; z++)
15093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const PixelBufferAccess		sliceAccess		= m_textureType == TEXTURETYPE_CUBE ? reference.getCubeFaceAccess((tcu::CubeFace)z) : reference.getSliceAccess(z);
15113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int					rowPitch		= sliceAccess.getRowPitch();
15123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				void *const					data			= sliceAccess.getDataPtr();
15133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int y = 0; y < imageSize.y(); y++)
15153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int x = 0; x < imageSize.x(); x++)
15163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
15183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					deMemcpy(scratchAccess.getDataPtr(), pixelData, pixelSize);
15203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (isFormatTypeInteger(m_imageFormat.type))
15223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						scratchAccess.setPixel(scratchAccess.getPixelUint(0, 0), 0, 0);
15233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					else
15243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						scratchAccess.setPixel(scratchAccess.getPixel(0, 0), 0, 0);
15253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					deMemcpy(pixelData, scratchAccess.getDataPtr(), pixelSize);
15273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
15283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
15293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int z = 0; z < numSlicesOrFaces; z++)
15323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < imageSize.y(); y++)
15333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < imageSize.x()/2; x++)
15343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (isIntegerTextureFormat)
15363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const UVec4 temp = reference.getPixelUint(imageSize.x()-1-x, y, z);
15383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixelUint(x, y, z));
15393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(x, y, z, temp);
15403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
15413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
15423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const Vec4 temp = reference.getPixel(imageSize.x()-1-x, y, z);
15443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixel(x, y, z));
15453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(x, y, z, temp);
15463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
15473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
15493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read texture 1 and compare to reference.
15513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture1, *texture1Buf, m_textureType, m_textureFormat, imageSize, ImageLayerComparer(reference));
15533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
15553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return STOP;
15563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
15573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15583c827367444ee418f129b2c238299f49d3264554Jarkko Poyryenum AtomicOperationCaseType
15593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_CASE_TYPE_END_RESULT = 0,	//!< Atomic case checks the end result of the operations, and not the return values.
15613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES,	//!< Atomic case checks the return values of the atomic function, and not the end result.
15623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ATOMIC_OPERATION_CASE_TYPE_LAST
15643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
15653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
15673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Binary atomic operation case.
15683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
15693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Case that performs binary atomic operations (i.e. any but compSwap) and
15703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * verifies according to the given AtomicOperationCaseType.
15713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
15723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * For the "end result" case type, a single texture (and image) is created,
15733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * upon which the atomic operations operate. A compute shader is dispatched
15743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * with dimensions equal to the image size, except with a bigger X size
15753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * so that every pixel is operated on by multiple invocations. The end
15763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * results are verified in BinaryAtomicOperationCase::EndResultVerifier.
15773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * The return values of the atomic function calls are ignored.
15783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
15793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * For the "return value" case type, the case does much the same operations
15803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * as in the "end result" case, but also creates an additional texture,
15813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * of size equal to the dispatch size, into which the return values of the
15823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * atomic functions are stored (with imageStore()). The return values are
15833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * verified in BinaryAtomicOperationCase::ReturnValueVerifier.
15843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * The end result values are not checked.
15853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
15863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * The compute shader invocations contributing to a pixel (X, Y, Z) in the
15873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * end result image are the invocations with global IDs
15883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * (X, Y, Z), (X+W, Y, Z), (X+2*W, Y, Z), ..., (X+(N-1)*W, Y, W), where W
15893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * is the width of the end result image and N is
15903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * BinaryAtomicOperationCase::NUM_INVOCATIONS_PER_PIXEL.
15913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
15923c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BinaryAtomicOperationCase : public TestCase
15933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
15953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									BinaryAtomicOperationCase		(Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperation operation, AtomicOperationCaseType caseType)
15963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase		(context, name, description)
15973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_format		(format)
15983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageType	(imageType)
15993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_operation	(operation)
16003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_caseType	(caseType)
16013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
16033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)		||
16043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  (m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT) && m_operation == ATOMIC_OPERATION_EXCHANGE));
16053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_operation != ATOMIC_OPERATION_COMP_SWAP);
16073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void							init							(void);
16103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult					iterate							(void);
16113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16123c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
16133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	class EndResultVerifier;
16143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	class ReturnValueVerifier;
16153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static int						getOperationInitialValue		(AtomicOperation op); //!< Appropriate value with which to initialize the texture.
16173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! Compute the argument given to the atomic function at the given invocation ID, when the entire dispatch has the given width and height.
16183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static int						getAtomicFuncArgument			(AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY);
16193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! Generate the shader expression for the argument given to the atomic function. x, y and z are the identifiers for the invocation ID components.
16203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static string					getAtomicFuncArgumentShaderStr	(AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY);
16213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const int				NUM_INVOCATIONS_PER_PIXEL = 5;
16233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat				m_format;
16253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType				m_imageType;
16263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperation			m_operation;
16273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperationCaseType	m_caseType;
16283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
16293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16303c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint BinaryAtomicOperationCase::getOperationInitialValue (AtomicOperation op)
16313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
16323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
16333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note 18 is just an arbitrary small nonzero value.
16353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:			return 18;
16363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:			return (1<<15) - 1;
16373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:			return 18;
16383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:			return (1<<15) - 1;
16393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:			return 18;
16403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:			return 18;
16413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:		return 18;
16423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
16433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
16443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return -1;
16453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
16473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16483c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint BinaryAtomicOperationCase::getAtomicFuncArgument (AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY)
16493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
16503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int x		= invocationID.x();
16513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int y		= invocationID.y();
16523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int z		= invocationID.z();
16533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int wid	= dispatchSizeXY.x();
16543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int hei	= dispatchSizeXY.y();
16553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
16573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Fall-throughs.
16593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:
16603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:
16613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:
16623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:
16633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:
16643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:
16653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return x*x + y*y + z*z;
16663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:
16683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return (z*wid + x)*hei + y;
16693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
16713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
16723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return -1;
16733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
16753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16763c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystring BinaryAtomicOperationCase::getAtomicFuncArgumentShaderStr (AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY)
16773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
16783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (op)
16793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Fall-throughs.
16813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_ADD:
16823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MIN:
16833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_MAX:
16843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_AND:
16853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_OR:
16863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_XOR:
16873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return "("+ x+"*"+x +" + "+ y+"*"+y +" + "+ z+"*"+z +")";
16883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case ATOMIC_OPERATION_EXCHANGE:
16903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return "((" + z + "*" + toString(dispatchSizeXY.x()) + " + " + x + ")*" + toString(dispatchSizeXY.y()) + " + " + y + ")";
16913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
16933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
16943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return DE_NULL;
16953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
16973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16983c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BinaryAtomicOperationCase::EndResultVerifier : public ImageLayerVerifier
16993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
17003c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
17013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	EndResultVerifier (AtomicOperation operation, TextureType imageType) : m_operation(operation), m_imageType(imageType) {}
17023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
17043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		isIntegerFormat		= isFormatTypeInteger(resultSlice.getFormat().type);
17063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec2		dispatchSizeXY		(NUM_INVOCATIONS_PER_PIXEL*resultSlice.getWidth(), resultSlice.getHeight());
17073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx),
17093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
17103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																				   : "slice " + toString(sliceOrFaceNdx)),
17113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  resultSlice);
17123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < resultSlice.getHeight(); y++)
17143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < resultSlice.getWidth(); x++)
17153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
17163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			union
17173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
17183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int		i;
17193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				float	f;
17203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			} result;
17213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (isIntegerFormat)
17233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				result.i = resultSlice.getPixelInt(x, y).x();
17243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
17253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				result.f = resultSlice.getPixel(x, y).x();
17263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Compute the arguments that were given to the atomic function in the invocations that contribute to this pixel.
17283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec3	invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
17303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		atomicArgs[NUM_INVOCATIONS_PER_PIXEL];
17313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
17333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
17343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
17353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				invocationGlobalIDs[i]	= gid;
17373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				atomicArgs[i]			= getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
17383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
17393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (isOrderIndependentAtomicOperation(m_operation))
17413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
17423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Just accumulate the atomic args (and the initial value) according to the operation, and compare.
17433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				DE_ASSERT(isIntegerFormat);
17453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int reference = getOperationInitialValue(m_operation);
17473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
17493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					reference = computeBinaryAtomicOperationResult(m_operation, reference, atomicArgs[i]);
17503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (result.i != reference)
17523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
17533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Failure: end result at pixel " << IVec2(x, y) << " of current layer is " << result.i << TestLog::EndMessage
17543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
17553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: data expression values for the IDs are " << arrayStr(atomicArgs) << TestLog::EndMessage
17563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: reference value is " << reference << TestLog::EndMessage;
17573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
17583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
17593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
17603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else if (m_operation == ATOMIC_OPERATION_EXCHANGE)
17613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
17623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Check that the end result equals one of the atomic args.
17633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool matchFound = false;
17653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++)
17673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					matchFound = isIntegerFormat ? result.i == atomicArgs[i]
17683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 : de::abs(result.f - (float)atomicArgs[i]) <= 0.01f;
17693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!matchFound)
17713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
17723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << (isIntegerFormat ? toString(result.i) : toString(result.f)) << TestLog::EndMessage
17733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< TestLog::Message << "// Note: expected one of " << arrayStr(atomicArgs) << TestLog::EndMessage;
17743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
17763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
17773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
17783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
17793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				DE_ASSERT(false);
17803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
17813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
17833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17853c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
17863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperation	m_operation;
17873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType		m_imageType;
17883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
17893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BinaryAtomicOperationCase::ReturnValueVerifier : public ImageLayerVerifier
17913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
17923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
17933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored.
17943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ReturnValueVerifier (AtomicOperation operation, TextureType imageType, const IVec2& endResultImageLayerSize) : m_operation(operation), m_imageType(imageType), m_endResultImageLayerSize(endResultImageLayerSize) {}
17953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
17973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		isIntegerFormat		(isFormatTypeInteger(resultSlice.getFormat().type));
17993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec2		dispatchSizeXY	(resultSlice.getWidth(), resultSlice.getHeight());
18003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(resultSlice.getWidth()	== NUM_INVOCATIONS_PER_PIXEL*m_endResultImageLayerSize.x()	&&
18023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  resultSlice.getHeight()	== m_endResultImageLayerSize.y()							&&
18033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  resultSlice.getDepth()	== 1);
18043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx),
18063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  "Per-Invocation Return Values, "
18073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
18083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	  : "slice " + toString(sliceOrFaceNdx)),
18093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  resultSlice);
18103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < m_endResultImageLayerSize.y(); y++)
18123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < m_endResultImageLayerSize.x(); x++)
18133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
18143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			union IntFloatArr
18153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int		i[NUM_INVOCATIONS_PER_PIXEL];
18173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				float	f[NUM_INVOCATIONS_PER_PIXEL];
18183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			};
18193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice.
18213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IntFloatArr		returnValues;
18233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IntFloatArr		atomicArgs;
18243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec3			invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
18253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2			pixelCoords[NUM_INVOCATIONS_PER_PIXEL];
18263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
18283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec2 pixCoord	(x + i*m_endResultImageLayerSize.x(), y);
18303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec3 gid			(pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
18313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				invocationGlobalIDs[i]	= gid;
18333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelCoords[i]			= pixCoord;
18343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (isIntegerFormat)
18363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
18373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					returnValues.i[i]	= resultSlice.getPixelInt(gid.x(), y).x();
18383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					atomicArgs.i[i]		= getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
18393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
18403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
18413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
18423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					returnValues.f[i]	= resultSlice.getPixel(gid.x(), y).x();
18433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					atomicArgs.f[i]		= (float)getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
18443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
18453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
18463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Verify that the return values form a valid sequence.
18483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const bool success = isIntegerFormat ? verifyOperationAccumulationIntermediateValues(m_operation,
18513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 getOperationInitialValue(m_operation),
18523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 atomicArgs.i,
18533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 returnValues.i)
18543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													 : verifyOperationAccumulationIntermediateValues(m_operation,
18563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 (float)getOperationInitialValue(m_operation),
18573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 atomicArgs.f,
18583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																									 returnValues.f);
18593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!success)
18613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
18623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
18633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< (isIntegerFormat ? arrayStr(returnValues.i) : arrayStr(returnValues.f)) << TestLog::EndMessage
18643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
18653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: data expression values for the IDs are "
18663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< (isIntegerFormat ? arrayStr(atomicArgs.i) : arrayStr(atomicArgs.f))
18673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< "; return values are not a valid result for any order of operations" << TestLog::EndMessage;
18683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
18693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
18703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
18713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
18723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
18743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
18753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18763c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
18773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperation	m_operation;
18783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType		m_imageType;
18793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec2				m_endResultImageLayerSize;
18803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! Check whether there exists an ordering of args such that { init*A", init*A*B, ..., init*A*B*...*LAST } is the "returnValues" sequence, where { A, B, ..., LAST } is args, and * denotes the operation.
18823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//	That is, whether "returnValues" is a valid sequence of intermediate return values when "operation" has been accumulated on "args" (and "init") in some arbitrary order.
18833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	template <typename T>
18843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static bool verifyOperationAccumulationIntermediateValues (AtomicOperation operation, T init, const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL])
18853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
18863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool argsUsed[NUM_INVOCATIONS_PER_PIXEL] = { false };
18873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return verifyRecursive(operation, 0, init, argsUsed, args, returnValues);
18893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
18903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static bool compare (int a, int b)		{ return a == b; }
18923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static bool compare (float a, float b)	{ return de::abs(a - b) <= 0.01f; }
18933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! Depth-first search for verifying the return value sequence.
18953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	template <typename T>
18963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static bool verifyRecursive (AtomicOperation operation, int index, T valueSoFar, bool (&argsUsed)[NUM_INVOCATIONS_PER_PIXEL], const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL])
18973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
18983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (index < NUM_INVOCATIONS_PER_PIXEL)
18993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
19003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
19013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
19023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!argsUsed[i] && compare(returnValues[i], valueSoFar))
19033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
19043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					argsUsed[i] = true;
19053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (verifyRecursive(operation, index+1, computeBinaryAtomicOperationResult(operation, valueSoFar, args[i]), argsUsed, args, returnValues))
19063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						return true;
19073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					argsUsed[i] = false;
19083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
19093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
19103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
19123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
19133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
19143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return true;
19153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
19173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19183c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BinaryAtomicOperationCase::init (void)
19193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1920a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
19213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
19223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1923a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
19243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
19253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19263c827367444ee418f129b2c238299f49d3264554Jarkko PoyryBinaryAtomicOperationCase::IterateResult BinaryAtomicOperationCase::iterate (void)
19273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
19283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx				= m_context.getRenderContext();
19293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log						(m_testCtx.getLog());
19303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
19313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
19323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
19333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize				= defaultImageSize(m_imageType);
19343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					numSlicesOrFaces		= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
19353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
19363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isIntFormat				= isFormatTypeSignedInteger(m_format.type);
19373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			endResultTextureBuf		(renderCtx);
19383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			returnValueTextureBuf	(renderCtx);
19393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			endResultTexture		(renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize.
19403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			returnValueTexture		(renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES.
19413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	 //	  Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL.
19423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
19443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup textures.
19463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage;
19483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_imageType == TEXTURETYPE_BUFFER)
19493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage;
19503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
19523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage;
19543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_imageType == TEXTURETYPE_BUFFER)
19553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage;
19563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Fill endResultTexture with initial pattern.
19593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
19623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
19643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const IVec4 initial(getOperationInitialValue(m_operation));
19653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int z = 0; z < numSlicesOrFaces; z++)
19673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int y = 0; y < imageSize.y(); y++)
19683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int x = 0; x < imageSize.x(); x++)
19693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				imageData.setPixel(x, y, z, initial);
19703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
19713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Upload initial pattern to endResultTexture and bind to image.
19733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glActiveTexture(GL_TEXTURE0);
19753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindTexture(textureTargetGL, *endResultTexture);
19763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTexParameteri(glLog, textureTargetGL);
19773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Filling end-result texture with initial pattern (initial value " << getOperationInitialValue(m_operation) << ")" << TestLog::EndMessage;
19793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		uploadTexture(glLog, imageData, *endResultTextureBuf);
19813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
19843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
19853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
19873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Set storage for returnValueTexture and bind to image.
19893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glActiveTexture(GL_TEXTURE1);
19913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindTexture(textureTargetGL, *returnValueTexture);
19923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTexParameteri(glLog, textureTargetGL);
19933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage;
19953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL,	1)
19963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																											 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1,							1)),
19973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  *returnValueTextureBuf);
19983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
20003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
20013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
20023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform image stores in compute shader and finalize reference computation.
20043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
20073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4";
20093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string atomicCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx % " + toString(imageSize.x())
20103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx % " + toString(imageSize.x()) + ", gy)"
20113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)";
20123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string invocationCoord		= m_imageType == TEXTURETYPE_BUFFER		? "gx"
20133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
20143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: "ivec3(gx, gy, gz)";
20153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string atomicArgExpr			= (isUintFormat		? "uint"
20163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											 : isIntFormat		? ""
20173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											 : "float")
20183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												+ getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec2(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y()));
20193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string atomicInvocation		= string() + getAtomicOperationShaderFuncName(m_operation) + "(u_results, " + atomicCoord + ", " + atomicArgExpr + ")";
20203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
20213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2022a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const std::string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
20233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
2025a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2026a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ imageAtomicExtensionShaderRequires(renderCtx)
2027a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
20283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
20293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
20303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
20313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
20323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n"
20333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
20343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															  "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n"
20353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: "") +
20363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
20373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
20383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
20393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gx = int(gl_GlobalInvocationID.x);\n"
20403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gy = int(gl_GlobalInvocationID.y);\n"
20413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gz = int(gl_GlobalInvocationID.z);\n"
20423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
20433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(" + atomicInvocation + "));\n"
20443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ?
20453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	" + atomicInvocation + ";\n"
20463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : DE_NULL) +
20473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
20483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
20503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
20523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
20543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
20553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
20563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
20573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
20583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
20603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
20623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
20643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
20653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
20663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read texture and check.
20683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32								textureToCheckGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTexture
20713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTexture
20723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: (deUint32)-1;
20733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32								textureToCheckBufGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTextureBuf
20743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTextureBuf
20753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: (deUint32)-1;
20763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec3									textureToCheckSize	= imageSize * IVec3(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? 1 : NUM_INVOCATIONS_PER_PIXEL, 1, 1);
20783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const UniquePtr<const ImageLayerVerifier>	verifier			(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? new EndResultVerifier(m_operation, m_imageType)
20793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	   : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES		? new ReturnValueVerifier(m_operation, m_imageType, imageSize.swizzle(0, 1))
20803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	   : (ImageLayerVerifier*)DE_NULL);
20813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, textureToCheckSize, *verifier))
20833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
20843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
20853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
20863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
20883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
20893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
20903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
20923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Atomic compSwap operation case.
20933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
20943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Similar in principle to BinaryAtomicOperationCase, but separated for
20953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * convenience, since the atomic function is somewhat different. Like
20963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * BinaryAtomicOperationCase, this has separate cases for checking end
20973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * result and return values.
20983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
20993c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass AtomicCompSwapCase : public TestCase
21003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21013c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
21023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									AtomicCompSwapCase		(Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperationCaseType caseType)
21033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase		(context, name, description)
21043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_format		(format)
21053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageType	(imageType)
21063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_caseType	(caseType)
21073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
21093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32));
21103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
21113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void							init					(void);
21133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult					iterate					(void);
21143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21153c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
21163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	class EndResultVerifier;
21173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	class ReturnValueVerifier;
21183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static int						getCompareArg			(const IVec3& invocationID, int imageWidth);
21203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static int						getAssignArg			(const IVec3& invocationID, int imageWidth);
21213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static string					getCompareArgShaderStr	(const string& x, const string& y, const string& z, int imageWidth);
21223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static string					getAssignArgShaderStr	(const string& x, const string& y, const string& z, int imageWidth);
21233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const int				NUM_INVOCATIONS_PER_PIXEL = 5;
21253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat				m_format;
21273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType				m_imageType;
21283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const AtomicOperationCaseType	m_caseType;
21293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
21303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint AtomicCompSwapCase::getCompareArg (const IVec3& invocationID, int imageWidth)
21323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int x							= invocationID.x();
21343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int y							= invocationID.y();
21353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int z							= invocationID.z();
21363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int wrapX						= x % imageWidth;
21373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int curPixelInvocationNdx		= x / imageWidth;
21383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return wrapX*wrapX + y*y + z*z + curPixelInvocationNdx*42;
21403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21423c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint AtomicCompSwapCase::getAssignArg (const IVec3& invocationID, int imageWidth)
21433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return getCompareArg(IVec3(invocationID.x() + imageWidth, invocationID.y(), invocationID.z()), imageWidth);
21453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystring AtomicCompSwapCase::getCompareArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
21483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const string wrapX					= "(" + x + "%" + toString(imageWidth) + ")";
21503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const string curPixelInvocationNdx	= "(" + x + "/" + toString(imageWidth) + ")";
21513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
21533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystring AtomicCompSwapCase::getAssignArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
21563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const string wrapX					= "(" + x + "%" + toString(imageWidth) + ")";
21583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const string curPixelInvocationNdx	= "(" + x + "/" + toString(imageWidth) + " + 1)";
21593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
21613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21633c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid AtomicCompSwapCase::init (void)
21643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2165a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
21663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
21673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2168a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
21693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21713c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass AtomicCompSwapCase::EndResultVerifier : public ImageLayerVerifier
21723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21733c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
21743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	EndResultVerifier (TextureType imageType, int imageWidth) : m_imageType(imageType), m_imageWidth(imageWidth) {}
21753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
21773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
21793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(resultSlice.getWidth() == m_imageWidth);
21803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx),
21823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
21833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																				   : "slice " + toString(sliceOrFaceNdx)),
21843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  resultSlice);
21853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < resultSlice.getHeight(); y++)
21873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < resultSlice.getWidth(); x++)
21883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Compute the value-to-assign arguments that were given to the atomic function in the invocations that contribute to this pixel.
21903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// One of those should be the result.
21913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	result = resultSlice.getPixelInt(x, y).x();
21933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec3		invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
21943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int			assignArgs[NUM_INVOCATIONS_PER_PIXEL];
21953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
21973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
21983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
21993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				invocationGlobalIDs[i]	= gid;
22013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				assignArgs[i]			= getAssignArg(gid, m_imageWidth);
22023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool matchFound = false;
22063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++)
22073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					matchFound = result == assignArgs[i];
22083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!matchFound)
22103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << result << TestLog::EndMessage
22123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
22133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: expected one of " << arrayStr(assignArgs)
22143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< " (those are the values given as the 'data' argument in the invocations that contribute to this pixel)"
22153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< TestLog::EndMessage;
22163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
22173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
22183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
22203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
22223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
22233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22243c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
22253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType	m_imageType;
22263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			m_imageWidth;
22273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
22283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22293c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass AtomicCompSwapCase::ReturnValueVerifier : public ImageLayerVerifier
22303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
22313c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
22323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored.
22333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ReturnValueVerifier (TextureType imageType, int endResultImageWidth) : m_imageType(imageType), m_endResultImageWidth(endResultImageWidth) {}
22343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
22363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
22373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
22383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageWidth);
22393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx),
22413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  "Per-Invocation Return Values, "
22423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								   + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
22433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	  : "slice " + toString(sliceOrFaceNdx)),
22443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							  resultSlice);
22453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < resultSlice.getHeight(); y++)
22473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < m_endResultImageWidth; x++)
22483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
22493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice.
22503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		returnValues[NUM_INVOCATIONS_PER_PIXEL];
22523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		compareArgs[NUM_INVOCATIONS_PER_PIXEL];
22533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec3	invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
22543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2	pixelCoords[NUM_INVOCATIONS_PER_PIXEL];
22553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
22573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec2 pixCoord	(x + i*m_endResultImageWidth, y);
22593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const IVec3 gid			(pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
22603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelCoords[i]			= pixCoord;
22623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				invocationGlobalIDs[i]	= gid;
22633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				returnValues[i]			= resultSlice.getPixelInt(gid.x(), y).x();
22643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				compareArgs[i]			= getCompareArg(gid, m_endResultImageWidth);
22653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Verify that the return values form a valid sequence.
22683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Due to the way the compare and assign arguments to the atomic calls are organized
22693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// among the different invocations contributing to the same pixel -- i.e. one invocation
22703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// compares to A and assigns B, another compares to B and assigns C, and so on, where
22718852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// A<B<C etc -- the first value in the return value sequence must be A, and each following
22728852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// value must be either the same as or the smallest value (among A, B, C, ...) bigger than
22738852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// the one just before it. E.g. sequences A A A A A A A A, A B C D E F G H and
22748852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// A A B B B C D E are all valid sequences (if there were 8 invocations contributing
22758852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// to each pixel).
22763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22788852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				int failingNdx = -1;
22793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22818852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					int currentAtomicValueNdx = 0;
22828852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
22833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
22848852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						if (returnValues[i] == compareArgs[currentAtomicValueNdx])
22858852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry							continue;
22868852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1])
22873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
22888852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry							currentAtomicValueNdx++;
22898852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry							continue;
22903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
22918852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						failingNdx = i;
22928852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						break;
22933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
22943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
22953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22968852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				if (failingNdx >= 0)
22973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
22993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											<< arrayStr(returnValues) << TestLog::EndMessage
23003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
23018852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						<< TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage
23028852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						<< TestLog::Message << "// Note: expected the return value sequence to fulfill the following conditions:\n"
23038852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry											<< "// - first value is " << compareArgs[0] << "\n"
23048852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry											<< "// - each value other than the first is either the same as the one just before it, or the smallest value (in the sequence "
23058852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry											<< arrayStr(compareArgs) << ") bigger than the one just before it" << TestLog::EndMessage;
23068852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					if (failingNdx == 0)
23078852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						log << TestLog::Message << "// Note: the first return value (" << returnValues[0] << ") isn't " << compareArgs[0] << TestLog::EndMessage;
23088852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					else
23098852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry						log << TestLog::Message << "// Note: the return value at index " << failingNdx << " (value " << returnValues[failingNdx] << ") "
23108852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry												<< "is neither " << returnValues[failingNdx-1] << " (the one just before it) "
23118852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry												<< "nor " << compareArgs[arrayIndexOf(compareArgs, returnValues[failingNdx-1])+1] << " (the smallest value bigger than the one just before it)"
23128852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry												<< TestLog::EndMessage;
23133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
23153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
23163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
23173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
23183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
23203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23223c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
23233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType	m_imageType;
23243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			m_endResultImageWidth;
23253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
23263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23273c827367444ee418f129b2c238299f49d3264554Jarkko PoyryAtomicCompSwapCase::IterateResult AtomicCompSwapCase::iterate (void)
23283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
23293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx				= m_context.getRenderContext();
23303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log						(m_testCtx.getLog());
23313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
23323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
23333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
23343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize				= defaultImageSize(m_imageType);
23353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					numSlicesOrFaces		= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
23363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
23373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isIntFormat				= isFormatTypeSignedInteger(m_format.type);
23383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			endResultTextureBuf		(renderCtx);
23393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			returnValueTextureBuf	(renderCtx);
23403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			endResultTexture		(renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize.
23413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			returnValueTexture		(renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES.
23423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	 //	  Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL.
23433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(isUintFormat || isIntFormat);
23453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
23473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup textures.
23493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage;
23513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_imageType == TEXTURETYPE_BUFFER)
23523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage;
23533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
23553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
23563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage;
23573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_imageType == TEXTURETYPE_BUFFER)
23583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage;
23593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Fill endResultTexture with initial pattern.
23623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
23643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
23653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
23673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int z = 0; z < numSlicesOrFaces; z++)
23683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int y = 0; y < imageSize.y(); y++)
23693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int x = 0; x < imageSize.x(); x++)
23703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				imageData.setPixel(x, y, z, IVec4(getCompareArg(IVec3(x, y, z), imageSize.x())));
23713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
23723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Upload initial pattern to endResultTexture and bind to image.
23743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glActiveTexture(GL_TEXTURE0);
23763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindTexture(textureTargetGL, *endResultTexture);
23773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTexParameteri(glLog, textureTargetGL);
23783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Filling end-result texture with initial pattern" << TestLog::EndMessage;
23803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		uploadTexture(glLog, imageData, *endResultTextureBuf);
23823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
23853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
23863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
23883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
23893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Set storage for returnValueTexture and bind to image.
23903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glActiveTexture(GL_TEXTURE1);
23923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindTexture(textureTargetGL, *returnValueTexture);
23933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTexParameteri(glLog, textureTargetGL);
23943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage;
23963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL,	1)
23973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																											 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1,							1)),
23983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  *returnValueTextureBuf);
23993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
24013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
24023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
24033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform atomics in compute shader.
24053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
24073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
24083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string colorScalarTypeName	= isUintFormat ? "uint" : isIntFormat ? "int" : DE_NULL;
24103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : DE_NULL) + "vec4";
24113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string atomicCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx % " + toString(imageSize.x())
24123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx % " + toString(imageSize.x()) + ", gy)"
24133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)";
24143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string invocationCoord		= m_imageType == TEXTURETYPE_BUFFER		? "gx"
24153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
24163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: "ivec3(gx, gy, gz)";
24173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
24183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2419a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const string glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
24203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
2422a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2423a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ imageAtomicExtensionShaderRequires(renderCtx)
2424a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
24253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
24263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
24273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
24283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
24293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n"
24303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
24313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															  "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n"
24323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: "") +
24333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
24343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
24353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
24363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gx = int(gl_GlobalInvocationID.x);\n"
24373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gy = int(gl_GlobalInvocationID.y);\n"
24383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gz = int(gl_GlobalInvocationID.z);\n"
24393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	" + colorScalarTypeName + " compare = " + colorScalarTypeName + getCompareArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
24403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	" + colorScalarTypeName + " data    = " + colorScalarTypeName + getAssignArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
24413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	" + colorScalarTypeName + " status  = " + colorScalarTypeName + "(-1);\n"
24423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	status = imageAtomicCompSwap(u_results, " + atomicCoord + ", compare, data);\n"
24433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
24443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(status));\n" :
24453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"") +
24463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
24473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
24493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
24513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
24533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
24543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
24553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
24563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
24573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
24593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
24613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
24633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
24643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
24653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Create reference, read texture and compare.
24673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
24693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32								textureToCheckGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTexture
24703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTexture
24713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: (deUint32)-1;
24723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32								textureToCheckBufGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTextureBuf
24743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTextureBuf
24753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: (deUint32)-1;
24763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// The relevant region of the texture being checked (potentially
24783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// different from actual texture size for cube maps, because cube maps
24793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// may have unused pixels due to square size restriction).
24803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec3									relevantRegion		= imageSize * (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT	? IVec3(1,							1,							1)
24813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																					 :														  IVec3(NUM_INVOCATIONS_PER_PIXEL,	1,							1));
24823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const UniquePtr<const ImageLayerVerifier>	verifier			(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? new EndResultVerifier(m_imageType, imageSize.x())
24843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	   : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES		? new ReturnValueVerifier(m_imageType, imageSize.x())
24853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	   : (ImageLayerVerifier*)DE_NULL);
24863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, relevantRegion, *verifier))
24883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
24893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
24903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
24913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
24933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
24943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
24953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Case testing the "coherent" or "volatile" qualifier, along with memoryBarrier() and barrier().
24973c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass CoherenceCase : public TestCase
24983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
24993c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
25003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum Qualifier
25013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
25023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		QUALIFIER_COHERENT = 0,
25033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		QUALIFIER_VOLATILE,
25043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		QUALIFIER_LAST
25063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
25073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CoherenceCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, Qualifier qualifier)
25093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase		(context, name, description)
25103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_format		(format)
25113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageType	(imageType)
25123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_qualifier	(qualifier)
25133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
25143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Y) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X) &&
25153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						 DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Z) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X));
25163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(qualifier == QUALIFIER_COHERENT || qualifier == QUALIFIER_VOLATILE);
25183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
25203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)		||
25213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				  m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT));
25223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
25233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2524a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
25253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult	iterate		(void);
25263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25273c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
25283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const int			SHADER_READ_OFFSETS_X[4];
25293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const int			SHADER_READ_OFFSETS_Y[4];
25303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const int			SHADER_READ_OFFSETS_Z[4];
25313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const char* const	SHADER_READ_OFFSETS_X_STR;
25323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const char* const	SHADER_READ_OFFSETS_Y_STR;
25333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const char* const	SHADER_READ_OFFSETS_Z_STR;
25343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat		m_format;
25363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType		m_imageType;
25373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const Qualifier			m_qualifier;
25383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
25393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25403c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst int			CoherenceCase::SHADER_READ_OFFSETS_X[4]		=		{ 1, 4, 7, 10 };
25413c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst int			CoherenceCase::SHADER_READ_OFFSETS_Y[4]		=		{ 2, 5, 8, 11 };
25423c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst int			CoherenceCase::SHADER_READ_OFFSETS_Z[4]		=		{ 3, 6, 9, 12 };
25433c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst char* const	CoherenceCase::SHADER_READ_OFFSETS_X_STR	= "int[]( 1, 4, 7, 10 )";
25443c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst char* const	CoherenceCase::SHADER_READ_OFFSETS_Y_STR	= "int[]( 2, 5, 8, 11 )";
25453c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst char* const	CoherenceCase::SHADER_READ_OFFSETS_Z_STR	= "int[]( 3, 6, 9, 12 )";
25463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25473c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCoherenceCase::IterateResult CoherenceCase::iterate (void)
25483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
25493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx					= m_context.getRenderContext();
25503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log							(m_testCtx.getLog());
25513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog						(renderCtx.getFunctions(), log);
25523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormatGL			= glu::getInternalFormat(m_format);
25533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL				= getGLTextureTarget(m_imageType);
25543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3&				imageSize					= defaultImageSize(m_imageType);
25553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					numSlicesOrFaces			= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
25563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isUintFormat				= isFormatTypeUnsignedInteger(m_format.type);
25573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool					isIntFormat					= isFormatTypeSignedInteger(m_format.type);
25583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char* const			qualifierName				= m_qualifier == QUALIFIER_COHERENT ? "coherent"
25593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: m_qualifier == QUALIFIER_VOLATILE ? "volatile"
25603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															: DE_NULL;
25613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			textureBuf					(renderCtx);
25623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			texture						(renderCtx);
25633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3					numGroups					= IVec3(16, de::min(16, imageSize.y()), de::min(2, numSlicesOrFaces));
25643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3					workItemSize				= IVec3(imageSize.x(), imageSize.y(), numSlicesOrFaces);
25653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3					localSize					= workItemSize / numGroups;
25663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3					minReqMaxLocalSize			= IVec3(128, 128, 64);
25673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int					minReqMaxLocalInvocations	= 128;
25683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(workItemSize == localSize*numGroups);
25703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(tcu::boolAll(tcu::lessThanEqual(localSize, minReqMaxLocalSize)));
25713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(localSize.x()*localSize.y()*localSize.z() <= minReqMaxLocalInvocations);
25723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_UNREF(minReqMaxLocalSize);
25733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_UNREF(minReqMaxLocalInvocations);
25743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
25763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup texture.
25783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
25803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_imageType == TEXTURETYPE_BUFFER)
25813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage;
25823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
25843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, *texture);
25853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
25863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize, *textureBuf);
25873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
25883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
25893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform computations in compute shader.
25913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
25933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
25943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
25953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4";
25963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const char* const	colorScalarTypeName		= isUintFormat ? "uint" : isIntFormat ? "int" : "float";
25973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		invocationCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx"
25983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
25993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: "ivec3(gx, gy, gz)";
26003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
26013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
26023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		localSizeX				= de::toString(localSize.x());
26033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		localSizeY				= de::toString(localSize.y());
26043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		localSizeZ				= de::toString(localSize.z());
2605a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const std::string	glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2606a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe
26073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
2609a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2610a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
26113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
26133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = " + localSizeX
26153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															+ ", local_size_y = " + localSizeY
26163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															+ ", local_size_z = " + localSizeZ
26173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															+ ") in;\n"
26183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) " + qualifierName + " uniform " + shaderImageTypeStr + " u_image;\n"
26193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
26203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
26213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gx = int(gl_GlobalInvocationID.x);\n"
26223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gy = int(gl_GlobalInvocationID.y);\n"
26233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int gz = int(gl_GlobalInvocationID.z);\n"
26243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(gx^gy^gz));\n"
26253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	memoryBarrier();\n"
26273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	barrier();\n"
26283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	" + colorScalarTypeName + " sum = " + colorScalarTypeName + "(0);\n"
26303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int groupBaseX = gx/" + localSizeX + "*" + localSizeX + ";\n"
26313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int groupBaseY = gy/" + localSizeY + "*" + localSizeY + ";\n"
26323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int groupBaseZ = gz/" + localSizeZ + "*" + localSizeZ + ";\n"
26333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int xOffsets[] = " + SHADER_READ_OFFSETS_X_STR + ";\n"
26343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int yOffsets[] = " + SHADER_READ_OFFSETS_Y_STR + ";\n"
26353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	int zOffsets[] = " + SHADER_READ_OFFSETS_Z_STR + ";\n"
26363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	for (int i = 0; i < " + toString(DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X)) + "; i++)\n"
26373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	{\n"
26383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"		int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n"
26393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"		int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n"
26403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"		int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n"
26413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"		sum += imageLoad(u_image, " + (m_imageType == TEXTURETYPE_BUFFER	? "readX"
26423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																							 : m_imageType == TEXTURETYPE_2D		? "ivec2(readX, readY)"
26433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																							 : "ivec3(readX, readY, readZ)") + ").x;\n"
26443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	}\n"
26453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	memoryBarrier();\n"
26473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	barrier();\n"
26483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
26493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
26503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
26513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
26533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
26553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
26573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
26583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
26593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
26603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
26613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
26633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
26653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glDispatchCompute(numGroups.x(), numGroups.y(), numGroups.z());
26673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
26683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
26693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Create reference, read texture and compare.
26713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
26733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		LayeredImage reference(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
26743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
26763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			LayeredImage base(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
26773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int z = 0; z < numSlicesOrFaces; z++)
26783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int y = 0; y < imageSize.y(); y++)
26793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int x = 0; x < imageSize.x(); x++)
26803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				base.setPixel(x, y, z, IVec4(x^y^z));
26813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int z = 0; z < numSlicesOrFaces; z++)
26833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int y = 0; y < imageSize.y(); y++)
26843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int x = 0; x < imageSize.x(); x++)
26853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
26863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	groupBaseX	= x / localSize.x() * localSize.x();
26873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	groupBaseY	= y / localSize.y() * localSize.y();
26883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	groupBaseZ	= z / localSize.z() * localSize.z();
26893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int			sum			= 0;
26903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int i = 0; i < DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X); i++)
26913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					sum += base.getPixelInt(groupBaseX + (x + SHADER_READ_OFFSETS_X[i]) % localSize.x(),
26923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											groupBaseY + (y + SHADER_READ_OFFSETS_Y[i]) % localSize.y(),
26933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											groupBaseZ + (z + SHADER_READ_OFFSETS_Z[i]) % localSize.z()).x();
26943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				reference.setPixel(x, y, z, IVec4(sum));
26963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
26973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
26983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
26993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_imageType, m_format, imageSize, ImageLayerComparer(reference)))
27003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
27013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
27023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
27033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
27053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
27063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
27073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27083c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass R32UIImageSingleValueVerifier : public ImageLayerVerifier
27093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
27103c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
27113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	R32UIImageSingleValueVerifier (const deUint32 value)					: m_min(value),	m_max(value)	{}
27123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	R32UIImageSingleValueVerifier (const deUint32 min, const deUint32 max)	: m_min(min),	m_max(max)		{}
27133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int) const
27153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
27163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(resultSlice.getWidth() == 1 && resultSlice.getHeight() == 1 && resultSlice.getDepth() == 1);
27173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(resultSlice.getFormat() == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32));
27183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Note: expecting to get value " << (m_min == m_max ? toString(m_min) : "in range [" + toString(m_min) + ", " + toString(m_max) + "]") << TestLog::EndMessage;
27203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32 resultValue = resultSlice.getPixelUint(0, 0).x();
27223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!de::inRange(resultValue, m_min, m_max))
27233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
27243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << TestLog::Message << "// Failure: got value " << resultValue << TestLog::EndMessage;
27253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
27263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
27273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
27283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
27293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << TestLog::Message << "// Success: got value " << resultValue << TestLog::EndMessage;
27303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return true;
27313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
27323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
27333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27343c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
27353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32 m_min;
27363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32 m_max;
27373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
27383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Tests the imageSize() GLSL function. Stores result in a 1x1 R32UI image. The image with which imageSize() is called isn't read or written, and
27403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//  can thus be qualifier readonly, writeonly, or both.
27413c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ImageSizeCase : public TestCase
27423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
27433c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
27443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum ImageAccess
27453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
27463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		IMAGEACCESS_READ_ONLY = 0,
27473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		IMAGEACCESS_WRITE_ONLY,
27483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		IMAGEACCESS_READ_ONLY_WRITE_ONLY,
27493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		IMAGEACCESS_LAST
27513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
27523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ImageSizeCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, const IVec3& size, ImageAccess imageAccess)
27543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase			(context, name, description)
27553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_format			(format)
27563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageType		(imageType)
27573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageSize		(size)
27583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_imageAccess		(imageAccess)
27593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
27603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
27613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2762a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
27633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult	iterate		(void);
27643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27653c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
27663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureFormat		m_format;
27673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TextureType		m_imageType;
27683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const IVec3				m_imageSize;
27693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const ImageAccess		m_imageAccess;
27703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
27713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27723c827367444ee418f129b2c238299f49d3264554Jarkko PoyryImageSizeCase::IterateResult ImageSizeCase::iterate (void)
27733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
27743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const RenderContext&		renderCtx				= m_context.getRenderContext();
27753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestLog&					log						(m_testCtx.getLog());
27763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
27773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
27783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
27793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Buffer			mainTextureBuf			(renderCtx);
27803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			mainTexture				(renderCtx);
27813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::Texture			shaderOutResultTexture	(renderCtx);
27823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
27843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup textures.
27863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *mainTexture << ")" << TestLog::EndMessage;
27883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_imageType == TEXTURETYPE_BUFFER)
27893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Message << "// Created a buffer for the texture (name " << *mainTextureBuf << ")" << TestLog::EndMessage;
27903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *shaderOutResultTexture << ") for storing the shader output" << TestLog::EndMessage;
27913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
27933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(textureTargetGL, *mainTexture);
27943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, textureTargetGL);
27953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, m_imageType, internalFormatGL, m_imageSize, *mainTextureBuf);
27963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(0, *mainTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
27973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
27983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
27993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE1);
28003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(GL_TEXTURE_2D, *shaderOutResultTexture);
28013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, GL_TEXTURE_2D);
28023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTextureStorage(glLog, TEXTURETYPE_2D, GL_R32UI, IVec3(1, 1, 1), 0 /* always 2d texture, no buffer needed */);
28033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(1, *shaderOutResultTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
28043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
28053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read texture size in compute shader.
28073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
28093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate compute shader.
28103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const char* const	shaderImageAccessStr	= m_imageAccess == IMAGEACCESS_READ_ONLY			? "readonly"
28123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: m_imageAccess == IMAGEACCESS_WRITE_ONLY			? "writeonly"
28133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: m_imageAccess == IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly writeonly"
28143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: DE_NULL;
28153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
28163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2817a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
28183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
2820a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2821a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
28223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
28233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp " + shaderImageTypeStr + ";\n"
28243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"precision highp uimage2D;\n"
28253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"\n"
28263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
28273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (" + shaderImageFormatStr + ", binding=0) " + shaderImageAccessStr + " uniform " + shaderImageTypeStr + " u_image;\n"
28283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"layout (r32ui, binding=1) writeonly uniform uimage2D u_result;\n"
28293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"void main (void)\n"
28303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"{\n"
28313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														+ (m_imageType == TEXTURETYPE_BUFFER ?
28323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	int result = imageSize(u_image);\n"
28333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE ?
28343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	ivec2 size = imageSize(u_image);\n"
28353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	int result = size.y*1000 + size.x;\n"
28363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY ?
28373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	ivec3 size = imageSize(u_image);\n"
28383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	int result = size.z*1000000 + size.y*1000 + size.x;\n"
28393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														 : DE_NULL) +
28403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"	imageStore(u_result, ivec2(0, 0), uvec4(result));\n"
28413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														"}\n"));
28423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
28443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
28463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
28483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
28493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
28503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
28513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
28523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and dispatch.
28543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
28563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glDispatchCompute(1, 1, 1);
28583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
28593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
28603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read texture and compare to reference.
28623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
28643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	referenceOutput		= m_imageType == TEXTURETYPE_BUFFER										? (deUint32)(												  m_imageSize.x())
28653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE		? (deUint32)(						   m_imageSize.y()*1000 + m_imageSize.x())
28663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY	? (deUint32)(m_imageSize.z()*1000000 + m_imageSize.y()*1000 + m_imageSize.x())
28673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											: (deUint32)-1;
28683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *shaderOutResultTexture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
28703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(referenceOutput)))
28713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
28723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
28733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
28743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
28763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
28773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
28783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Case testing the control over early/late fragment tests.
28803c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass EarlyFragmentTestsCase : public TestCase
28813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
28823c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
28833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum TestType
28843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
28853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TESTTYPE_DEPTH = 0,
28863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TESTTYPE_STENCIL,
28873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
28883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TESTTYPE_LAST
28893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
28903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2891a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	enum RenderTargetType
2892a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	{
2893a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		RENDERTARGET_DEFAULT = 0,
2894a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		RENDERTARGET_FBO,
2895a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT,
2896a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2897a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		RENDERTARGET_LAST
2898a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	};
2899a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2900a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2901a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	EarlyFragmentTestsCase (Context& context, const char* name, const char* description, TestType type, bool useEarlyTests, RenderTargetType renderTarget)
29023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: TestCase			(context, name, description)
29033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_type			(type)
29043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_useEarlyTests	(useEarlyTests)
2905a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		, m_renderTarget	(renderTarget)
29063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
29073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
29083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void init (void)
29103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
29113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) == 0)
29123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::NotSupportedError("GL_MAX_FRAGMENT_IMAGE_UNIFORMS is zero");
29133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2914a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
29153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
29163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2917653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos		if (m_type == TESTTYPE_DEPTH				&&
2918a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			m_renderTarget == RENDERTARGET_DEFAULT	&&
2919a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			m_context.getRenderTarget().getDepthBits() == 0)
2920a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		{
2921a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			throw tcu::NotSupportedError("Test requires depth buffer");
2922a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		}
2923a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2924653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos		if (m_type == TESTTYPE_STENCIL				&&
2925a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			m_renderTarget == RENDERTARGET_DEFAULT	&&
2926a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			m_context.getRenderTarget().getStencilBits() == 0)
2927a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		{
2928a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			throw tcu::NotSupportedError("Test requires stencil buffer");
2929a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		}
2930a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2931a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		if (m_renderTarget == RENDERTARGET_DEFAULT	&&
2932a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			(m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE))
29333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::NotSupportedError("Render target must have at least " + toString(RENDER_SIZE) + " width and height");
29343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
29353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult iterate (void);
29373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29383c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
2939653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos	static const int		RENDER_SIZE;
29403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2941a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const TestType			m_type;
2942a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const bool				m_useEarlyTests;
2943653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos	const RenderTargetType	m_renderTarget;
29443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
29453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29463c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst int EarlyFragmentTestsCase::RENDER_SIZE = 32;
29473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29483c827367444ee418f129b2c238299f49d3264554Jarkko PoyryEarlyFragmentTestsCase::IterateResult EarlyFragmentTestsCase::iterate (void)
29493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2950a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const RenderContext&			renderCtx			= m_context.getRenderContext();
2951a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	TestLog&						log					(m_testCtx.getLog());
2952a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	glu::CallLogWrapper				glLog				(renderCtx.getFunctions(), log);
2953a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	de::Random						rnd					(deStringHash(getName()));
2954a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const bool						expectPartialResult	= m_useEarlyTests && m_renderTarget != RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT;
2955a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const int						viewportWidth		= RENDER_SIZE;
2956a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const int						viewportHeight		= RENDER_SIZE;
2957a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const int						viewportX			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getWidth() - viewportWidth))	: (0);
2958a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const int						viewportY			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getHeight() - viewportHeight))	: (0);
2959a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	const glu::Texture				texture				(renderCtx);
2960a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	de::MovePtr<glu::Framebuffer>	fbo;
2961653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos	de::MovePtr<glu::Renderbuffer>	colorAttachment;
2962653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos	de::MovePtr<glu::Renderbuffer>	testAttachment;
29633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.enableLogging(true);
29653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup texture.
29673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
29693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
29703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glActiveTexture(GL_TEXTURE0);
29713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindTexture(GL_TEXTURE_2D, *texture);
29723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	setTexParameteri(glLog, GL_TEXTURE_2D);
29733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
29743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		LayeredImage src(TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 1, 1, 1);
29753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src.setPixel(0, 0, 0, IVec4(0));
29763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		uploadTexture(glLog, src, 0 /* always 2d texture, no buffer needed */);
29773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
29783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32UI);
29793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
29803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2981a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	// Set up framebuffer
2982a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	if (m_renderTarget == RENDERTARGET_FBO ||
2983a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		m_renderTarget == RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)
2984a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	{
2985653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos		fbo				= de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx));
2986a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		colorAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
2987a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		testAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
2988a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2989a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		glLog.glBindRenderbuffer(GL_RENDERBUFFER, **colorAttachment);
2990a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
2991a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen color attachment rb");
2992a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2993a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		glLog.glBindFramebuffer(GL_FRAMEBUFFER, **fbo);
2994a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
2995a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo color attachment");
2996a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
2997a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_DEPTH)
2998a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		{
2999a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
3000a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, RENDER_SIZE, RENDER_SIZE);
3001a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen depth attachment rb");
3002a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
3003a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3004a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo depth attachment");
3005a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		}
3006a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		else if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_STENCIL)
3007a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		{
3008a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
3009a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, RENDER_SIZE, RENDER_SIZE);
3010a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen stencil attachment rb");
3011a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
3012a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3013a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo stencil attachment");
3014a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		}
3015a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
3016a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
3017a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "setup fbo");
3018a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
3019a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry	}
3020a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry
30213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Set up appropriate conditions for the test.
30223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
30243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glLog.glClear(GL_COLOR_BUFFER_BIT);
30253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_type == TESTTYPE_DEPTH)
30273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
30283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClearDepthf(0.5f);
30293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClear(GL_DEPTH_BUFFER_BIT);
30303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glEnable(GL_DEPTH_TEST);
30313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
30323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (m_type == TESTTYPE_STENCIL)
30333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
30343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClearStencil(0);
30353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClear(GL_STENCIL_BUFFER_BIT);
30363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glScissor(viewportX, viewportY, viewportWidth/2, viewportHeight);
30373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glEnable(GL_SCISSOR_TEST);
30383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClearStencil(1);
30393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glClear(GL_STENCIL_BUFFER_BIT);
30403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glDisable(GL_SCISSOR_TEST);
30413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glStencilFunc(GL_EQUAL, 1, 1);
30423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
30433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glEnable(GL_STENCIL_TEST);
30443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
30453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
30463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(false);
30473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform image stores in fragment shader.
30493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3051a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe		const std::string glslVersionDeclaration = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
3052a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe
30533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Generate fragment shader.
30543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::ShaderProgram program(renderCtx,
3056a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe			glu::ProgramSources() << glu::VertexSource(		glslVersionDeclaration + "\n"
30573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"highp in vec3 a_position;\n"
30593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"void main (void)\n"
30613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"{\n"
30623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	gl_Position = vec4(a_position, 1.0);\n"
30633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"}\n")
30643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3065a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe								  << glu::FragmentSource(	glslVersionDeclaration + "\n"
3066a679f0bab1149897da5f33f614f4f205810c92ebDaniel Andrade Groppe															+ imageAtomicExtensionShaderRequires(renderCtx) +
30673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															+ string(m_useEarlyTests ? "layout (early_fragment_tests) in;\n\n" : "") +
30693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"layout (location = 0) out highp vec4 o_color;\n"
30703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"precision highp uimage2D;\n"
30723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"layout (r32ui, binding=0) coherent uniform uimage2D u_image;\n"
30743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"\n"
30753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"void main (void)\n"
30763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"{\n"
30773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	imageAtomicAdd(u_image, ivec2(0, 0), uint(1));\n"
30783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"	o_color = vec4(1.0);\n"
30793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry															"}\n"));
30803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
30823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << program;
30843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!program.isOk())
30863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
30873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
30883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return STOP;
30893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
30903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Setup and draw full-viewport quad.
30923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glLog.glUseProgram(program.getProgram());
30943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
30953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
30963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			static const float vertexPositions[4*3] =
30973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
30983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				-1.0, -1.0, -1.0f,
30993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				 1.0, -1.0,  0.0f,
31003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				-1.0,  1.0,  0.0f,
31013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				 1.0,  1.0,  1.0f,
31023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			};
31033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
31053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VertexArrayBinding attrBindings[] =
31073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
31083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glu::va::Float("a_position", 3, 4, 0, &vertexPositions[0])
31093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			};
31103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glLog.glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
31123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
31143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
31153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Draw failed");
31163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
31173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
31183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Log rendered result for convenience.
31203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
31213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Surface rendered(viewportWidth, viewportHeight);
31223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::readPixels(renderCtx, viewportX, viewportY, rendered.getAccess());
31233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << TestLog::Image("Rendered", "Rendered image", rendered);
31243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
31253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read counter value and check.
31273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
31283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int numSamples		= de::max(1, renderCtx.getRenderTarget().getNumSamples());
3129a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		const int expectedCounter	= expectPartialResult ? viewportWidth*viewportHeight/2				: viewportWidth*viewportHeight;
3130a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		const int tolerance			= expectPartialResult ? de::max(viewportWidth, viewportHeight)*3	: 0;
31313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int expectedMin		= de::max(0, expectedCounter - tolerance);
31323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int expectedMax		= (expectedCounter + tolerance) * numSamples;
31333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *texture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
31353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(expectedMin, expectedMax)))
31363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
31373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
31383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
31393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return STOP;
31413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
31423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
31433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // anonymous
31453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31463c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context)
31473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests")
31483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
31493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
31503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31513c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void)
31523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
31533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
31543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31553c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderImageLoadStoreTests::init (void)
31563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
31573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Per-image-type tests.
31583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
31603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		static const TextureType imageTypes[] =
31613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
31623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TEXTURETYPE_2D,
31633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TEXTURETYPE_CUBE,
31643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TEXTURETYPE_3D,
31653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TEXTURETYPE_2D_ARRAY,
31663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TEXTURETYPE_BUFFER
31673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
31683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		static const TextureFormat formats[] =
31703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
31713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT),
31723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::HALF_FLOAT),
31733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::R,		TextureFormat::FLOAT),
31743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT32),
31763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16),
31773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8),
31783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT32),
31793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT32),
31813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16),
31823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8),
31833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT32),
31843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8),
31863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT8)
31883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
31893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageTypes); imageTypeNdx++)
31913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
31923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const TextureType		imageType			= imageTypes[imageTypeNdx];
31933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	imageTypeGroup		= new TestCaseGroup(m_context, getTextureTypeName(imageType), "");
31943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			addChild(imageTypeGroup);
31953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
31963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	storeGroup			= new TestCaseGroup(m_context, "store",					"Plain imageStore() cases");
31973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	loadStoreGroup		= new TestCaseGroup(m_context, "load_store",			"Cases with imageLoad() followed by imageStore()");
31983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	atomicGroup			= new TestCaseGroup(m_context, "atomic",				"Atomic image operation cases");
31993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	qualifierGroup		= new TestCaseGroup(m_context, "qualifiers",			"Coherent, volatile and restrict");
32003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	reinterpretGroup	= new TestCaseGroup(m_context, "format_reinterpret",	"Cases with differing texture and image formats");
32013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestCaseGroup* const	imageSizeGroup		= new TestCaseGroup(m_context, "image_size",			"imageSize() cases");
32023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(storeGroup);
32033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(loadStoreGroup);
32043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(atomicGroup);
32053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(qualifierGroup);
32063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(reinterpretGroup);
32073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageTypeGroup->addChild(imageSizeGroup);
32083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
32103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
32113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const TextureFormat&	format		= formats[formatNdx];
32123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const string			formatName	= getShaderImageFormatQualifier(formats[formatNdx]);
32133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(format))
32153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					continue;
32163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Store cases.
32183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				storeGroup->addChild(new ImageStoreCase(m_context, formatName.c_str(), "", format, imageType));
32203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (textureLayerType(imageType) != imageType)
32213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					storeGroup->addChild(new ImageStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
32223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Load & store.
32243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, formatName.c_str(), "", format, imageType));
32263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (textureLayerType(imageType) != imageType)
32273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageLoadAndStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
32283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (format.order == TextureFormat::R)
32303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
32313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Atomic operations.
32323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int operationI = 0; operationI < ATOMIC_OPERATION_LAST; operationI++)
32343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
32353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						for (int atomicCaseTypeI = 0; atomicCaseTypeI < ATOMIC_OPERATION_CASE_TYPE_LAST; atomicCaseTypeI++)
32363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
32373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							const AtomicOperation operation = (AtomicOperation)operationI;
32383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							if (format.type == TextureFormat::FLOAT && operation != ATOMIC_OPERATION_EXCHANGE)
32403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								continue;
32413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							const AtomicOperationCaseType	caseType		= (AtomicOperationCaseType)atomicCaseTypeI;
32433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							const string					caseTypeName	= caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? "result"
32443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																			: caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? "return_value"
32453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																			: DE_NULL;
32463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							const string					caseName		= string() + getAtomicOperationCaseName(operation) + "_" + formatName + "_" + caseTypeName;
32473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							if (operation == ATOMIC_OPERATION_COMP_SWAP)
32493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								atomicGroup->addChild(new AtomicCompSwapCase(m_context, caseName.c_str(), "", format, imageType, caseType));
32503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							else
32513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								atomicGroup->addChild(new BinaryAtomicOperationCase(m_context, caseName.c_str(), "", format, imageType, operation, caseType));
32523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
32533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
32543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Coherence.
32563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int coherenceQualifierI = 0; coherenceQualifierI < CoherenceCase::QUALIFIER_LAST; coherenceQualifierI++)
32583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
32593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const CoherenceCase::Qualifier	coherenceQualifier		= (CoherenceCase::Qualifier)coherenceQualifierI;
32603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const char* const				coherenceQualifierName	= coherenceQualifier == CoherenceCase::QUALIFIER_COHERENT ? "coherent"
32613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																				: coherenceQualifier == CoherenceCase::QUALIFIER_VOLATILE ? "volatile"
32623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																				: DE_NULL;
32633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const string					caseName				= string() + coherenceQualifierName + "_" + formatName;
32643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						qualifierGroup->addChild(new CoherenceCase(m_context, caseName.c_str(), "", format, imageType, coherenceQualifier));
32663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
32673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
32683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
32693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Restrict.
32713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			qualifierGroup->addChild(new ImageLoadAndStoreCase(m_context, "restrict", "", TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), imageType, ImageLoadAndStoreCase::CASEFLAG_RESTRICT_IMAGES));
32723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Format re-interpretation.
32743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int texFmtNdx = 0; texFmtNdx < DE_LENGTH_OF_ARRAY(formats); texFmtNdx++)
32763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int imgFmtNdx = 0; imgFmtNdx < DE_LENGTH_OF_ARRAY(formats); imgFmtNdx++)
32773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
32783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const TextureFormat& texFmt = formats[texFmtNdx];
32793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const TextureFormat& imgFmt = formats[imgFmtNdx];
32803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(texFmt))
32823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					continue;
32833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (texFmt != imgFmt && texFmt.getPixelSize() == imgFmt.getPixelSize())
32853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					reinterpretGroup->addChild(new ImageLoadAndStoreCase(m_context,
32863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		 (getShaderImageFormatQualifier(texFmt) + "_" + getShaderImageFormatQualifier(imgFmt)).c_str(), "",
32873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		 texFmt, imgFmt, imageType));
32883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
32893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// imageSize().
32913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
32923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
32933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				static const IVec3 baseImageSizes[] =
32943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
32953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					IVec3(32, 32, 32),
32963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					IVec3(12, 34, 56),
32973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					IVec3(1,   1,  1),
32983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					IVec3(7,   1,  1)
32993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				};
33003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int imageAccessI = 0; imageAccessI < ImageSizeCase::IMAGEACCESS_LAST; imageAccessI++)
33023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
33033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const ImageSizeCase::ImageAccess	imageAccess		= (ImageSizeCase::ImageAccess)imageAccessI;
33043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const char* const					imageAccessStr	= imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY				? "readonly"
33053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: imageAccess == ImageSizeCase::IMAGEACCESS_WRITE_ONLY				? "writeonly"
33063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly_writeonly"
33073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																		: DE_NULL;
33083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(baseImageSizes); imageSizeNdx++)
33103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
33113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const IVec3&	baseSize	= baseImageSizes[imageSizeNdx];
33123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const IVec3		imageSize	= imageType == TEXTURETYPE_BUFFER		? IVec3(baseSize.x(), 1, 1)
33133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_2D			? IVec3(baseSize.x(), baseSize.y(), 1)
33143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_CUBE			? IVec3(baseSize.x(), baseSize.x(), 1)
33153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_3D			? baseSize
33163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_2D_ARRAY		? baseSize
33173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: IVec3(-1, -1, -1);
33183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const string	sizeStr		= imageType == TEXTURETYPE_BUFFER		? toString(imageSize.x())
33203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_2D			? toString(imageSize.x()) + "x" + toString(imageSize.y())
33213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_CUBE			? toString(imageSize.x()) + "x" + toString(imageSize.y())
33223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_3D			? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
33233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: imageType == TEXTURETYPE_2D_ARRAY		? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
33243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													: DE_NULL;
33253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const string	caseName	= string() + imageAccessStr + "_" + sizeStr;
33273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						imageSizeGroup->addChild(new ImageSizeCase(m_context, caseName.c_str(), "", TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), imageType, imageSize, imageAccess));
33293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
33303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
33313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
33323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
33333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
33343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// early_fragment_tests cases.
33363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
33383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TestCaseGroup* const earlyTestsGroup = new TestCaseGroup(m_context, "early_fragment_tests", "");
33393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		addChild(earlyTestsGroup);
33403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3341a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		for (int testRenderTargetI = 0; testRenderTargetI < EarlyFragmentTestsCase::RENDERTARGET_LAST; testRenderTargetI++)
33423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int useEarlyTestsI = 0; useEarlyTestsI <= 1; useEarlyTestsI++)
3343a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry		for (int testTypeI = 0; testTypeI < EarlyFragmentTestsCase::TESTTYPE_LAST; testTypeI++)
33443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3345a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			const EarlyFragmentTestsCase::RenderTargetType	targetType		= (EarlyFragmentTestsCase::RenderTargetType)testRenderTargetI;
3346653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos			const bool										useEarlyTests	= useEarlyTestsI != 0;
3347a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			const EarlyFragmentTestsCase::TestType			testType		= (EarlyFragmentTestsCase::TestType)testTypeI;
33483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3349a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			const string									testTypeName	= testType == EarlyFragmentTestsCase::TESTTYPE_DEPTH	? "depth"
3350a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			: testType == EarlyFragmentTestsCase::TESTTYPE_STENCIL	? "stencil"
3351a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			: DE_NULL;
33523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3353653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos			const string									targetName		= targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO							? (std::string("_fbo"))
3354a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			: targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT	? (std::string("_fbo_with_no_") + testTypeName)
3355a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			: std::string("");
33563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3357a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			const string									caseName		= string(useEarlyTests ? "" : "no_") + "early_fragment_tests_" + testTypeName + targetName;
33583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3359a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			const string									caseDesc		= string(useEarlyTests ? "Specify" : "Don't specify")
3360a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			+ " early_fragment_tests, use the " + testTypeName + " test"
3361653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos																			+ ((targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO)								? (", render to fbo")
3362653ad0e8a4209754304cbd5b5ceb4fdc7b29c01aPyry Haulos																			   : (targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)	? (", render to fbo without relevant buffer")
3363a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry																			   : (""));
33643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3365a237fcd566c01e1c84401b68d6d3687d8040dfb2Jarkko Pöyry			earlyTestsGroup->addChild(new EarlyFragmentTestsCase(m_context, caseName.c_str(), caseDesc.c_str(), testType, useEarlyTests, targetType));
33663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
33673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
33683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
33693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
33703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // Functional
33713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // gles31
33723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // deqp
3373