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