Home | History | Annotate | Download | only in robustness
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2018 The Khronos Group Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Robust buffer access tests for storage buffers and
     22  *        storage texel buffers with variable pointers.
     23  *
     24  * \note These tests are checking if accessing a memory through a variable
     25  *       pointer that points outside of accessible buffer memory is robust.
     26  *       To do this the tests are creating proper SPIRV code that creates
     27  *       variable pointers. Those pointers are either pointing into a
     28  *       memory allocated for a buffer but "not accesible" - meaning
     29  *       DescriptorBufferInfo has smaller size than a memory we access in
     30  *       shader or entirely outside of allocated memory (i.e. buffer is
     31  *       256 bytes big but we are trying to access under offset of 1k from
     32  *       buffer start). There is a set of valid behaviours defined when
     33  *       robust buffer access extension is enabled described in chapter 32
     34  *       section 1 of Vulkan spec.
     35  *
     36  *//*--------------------------------------------------------------------*/
     37 
     38 #include "vktRobustBufferAccessWithVariablePointersTests.hpp"
     39 #include "vktRobustnessUtil.hpp"
     40 #include "vktTestCaseUtil.hpp"
     41 #include "vkBuilderUtil.hpp"
     42 #include "vkImageUtil.hpp"
     43 #include "vkPrograms.hpp"
     44 #include "vkQueryUtil.hpp"
     45 #include "vkRef.hpp"
     46 #include "vkRefUtil.hpp"
     47 #include "vkTypeUtil.hpp"
     48 #include "tcuTestLog.hpp"
     49 #include "vkDefs.hpp"
     50 #include "deRandom.hpp"
     51 
     52 #include <limits>
     53 #include <sstream>
     54 
     55 namespace vkt
     56 {
     57 namespace robustness
     58 {
     59 
     60 using namespace vk;
     61 
     62 // keep local things local
     63 namespace
     64 {
     65 
     66 // A function for getting information on variable pointer features supported through physical device
     67 vk::VkPhysicalDeviceVariablePointerFeatures querySupportedVariablePointersFeatures (const deUint32					apiVersion,
     68 																					const InstanceInterface&		vki,
     69 																					VkPhysicalDevice				device,
     70 																					const std::vector<std::string>&	instanceExtensions)
     71 {
     72 	VkPhysicalDeviceVariablePointerFeatures extensionFeatures =
     73 	{
     74 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR,	// sType
     75 		DE_NULL,															// pNext
     76 		false,																// variablePointersStorageBuffer
     77 		false,																// variablePointers
     78 	};
     79 
     80 	VkPhysicalDeviceFeatures2	features;
     81 	deMemset(&features, 0, sizeof(features));
     82 	features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
     83 	features.pNext = &extensionFeatures;
     84 
     85 	// Call the getter only if supported. Otherwise above "zero" defaults are used
     86 	if (isInstanceExtensionSupported(apiVersion, instanceExtensions, "VK_KHR_get_physical_device_properties2"))
     87 	{
     88 		vki.getPhysicalDeviceFeatures2(device, &features);
     89 	}
     90 
     91 	return extensionFeatures;
     92 }
     93 
     94 // A supplementary structures that can hold information about buffer size
     95 struct AccessRangesData
     96 {
     97 	VkDeviceSize	allocSize;
     98 	VkDeviceSize	accessRange;
     99 	VkDeviceSize	maxAccessRange;
    100 };
    101 
    102 // Pointer to function that can be used to fill a buffer with some data - it is passed as an parameter to buffer creation utility function
    103 typedef void(*FillBufferProcPtr)(void*, vk::VkDeviceSize, const void* const);
    104 
    105 // An utility function for creating a buffer
    106 // This function not only allocates memory for the buffer but also fills buffer up with a data
    107 void createTestBuffer (const vk::DeviceInterface&				deviceInterface,
    108 					   const VkDevice&							device,
    109 					   VkDeviceSize								accessRange,
    110 					   VkBufferUsageFlags						usage,
    111 					   SimpleAllocator&							allocator,
    112 					   Move<VkBuffer>&							buffer,
    113 					   de::MovePtr<Allocation>&					bufferAlloc,
    114 					   AccessRangesData&						data,
    115 					   FillBufferProcPtr						fillBufferProc,
    116 					   const void* const						blob)
    117 {
    118 	const VkBufferCreateInfo	bufferParams	=
    119 	{
    120 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
    121 		DE_NULL,									// const void*			pNext;
    122 		0u,											// VkBufferCreateFlags	flags;
    123 		accessRange,								// VkDeviceSize			size;
    124 		usage,										// VkBufferUsageFlags	usage;
    125 		VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
    126 		VK_QUEUE_FAMILY_IGNORED,					// deUint32				queueFamilyIndexCount;
    127 		DE_NULL										// const deUint32*		pQueueFamilyIndices;
    128 	};
    129 
    130 	buffer = createBuffer(deviceInterface, device, &bufferParams);
    131 
    132 	VkMemoryRequirements bufferMemoryReqs		= getBufferMemoryRequirements(deviceInterface, device, *buffer);
    133 	bufferAlloc = allocator.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
    134 
    135 	data.allocSize = bufferMemoryReqs.size;
    136 	data.accessRange = accessRange;
    137 	data.maxAccessRange = deMinu64(data.allocSize, deMinu64(bufferParams.size, accessRange));
    138 
    139 	VK_CHECK(deviceInterface.bindBufferMemory(device, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
    140 	fillBufferProc(bufferAlloc->getHostPtr(), bufferMemoryReqs.size, blob);
    141 	flushMappedMemoryRange(deviceInterface, device, bufferAlloc->getMemory(), bufferAlloc->getOffset(), VK_WHOLE_SIZE);
    142 }
    143 
    144 // An adapter function matching FillBufferProcPtr interface. Fills a buffer with "randomly" generated test data matching desired format.
    145 void populateBufferWithValues (void*				buffer,
    146 							   VkDeviceSize			size,
    147 							   const void* const	blob)
    148 {
    149 	populateBufferWithTestValues(buffer, size, *static_cast<const vk::VkFormat*>(blob));
    150 }
    151 
    152 // An adapter function matching FillBufferProcPtr interface. Fills a buffer with 0xBABABABABABA... pattern. Used to fill up output buffers.
    153 // Since this pattern cannot show up in generated test data it should not show up in the valid output.
    154 void populateBufferWithDummy (void*					buffer,
    155 							  VkDeviceSize			size,
    156 							  const void* const		blob)
    157 {
    158 	DE_UNREF(blob);
    159 	deMemset(buffer, 0xBA, static_cast<size_t>(size));
    160 }
    161 
    162 // An adapter function matching FillBufferProcPtr interface. Fills a buffer with a copy of memory contents pointed to by blob.
    163 void populateBufferWithCopy (void*					buffer,
    164 							 VkDeviceSize			size,
    165 							 const void* const		blob)
    166 {
    167 	deMemcpy(buffer, blob, static_cast<size_t>(size));
    168 }
    169 
    170 // A composite types used in test
    171 // Those composites can be made of unsigned ints, signed ints or floats (except for matrices that work with floats only).
    172 enum ShaderType
    173 {
    174 	SHADER_TYPE_MATRIX_COPY					= 0,
    175 	SHADER_TYPE_VECTOR_COPY,
    176 	SHADER_TYPE_SCALAR_COPY,
    177 
    178 	SHADER_TYPE_COUNT
    179 };
    180 
    181 // We are testing reads or writes
    182 // In case of testing reads - writes are always
    183 enum BufferAccessType
    184 {
    185 	BUFFER_ACCESS_TYPE_READ_FROM_STORAGE	= 0,
    186 	BUFFER_ACCESS_TYPE_WRITE_TO_STORAGE,
    187 };
    188 
    189 // Test case for checking robust buffer access with variable pointers
    190 class RobustAccessWithPointersTest : public vkt::TestCase
    191 {
    192 public:
    193 	static const deUint32		s_testArraySize;
    194 	static const deUint32		s_numberOfBytesAccessed;
    195 
    196 								RobustAccessWithPointersTest	(tcu::TestContext&		testContext,
    197 																 const std::string&		name,
    198 																 const std::string&		description,
    199 																 VkShaderStageFlags		shaderStage,
    200 																 ShaderType				shaderType,
    201 																 VkFormat				bufferFormat);
    202 
    203 	virtual						~RobustAccessWithPointersTest	(void)
    204 	{
    205 	}
    206 
    207 protected:
    208 	const VkShaderStageFlags	m_shaderStage;
    209 	const ShaderType			m_shaderType;
    210 	const VkFormat				m_bufferFormat;
    211 };
    212 
    213 const deUint32 RobustAccessWithPointersTest::s_testArraySize = 1024u;
    214 const deUint32 RobustAccessWithPointersTest::s_numberOfBytesAccessed = static_cast<deUint32>(16ull * sizeof(float));
    215 
    216 RobustAccessWithPointersTest::RobustAccessWithPointersTest(tcu::TestContext&		testContext,
    217 	const std::string&		name,
    218 	const std::string&		description,
    219 	VkShaderStageFlags		shaderStage,
    220 	ShaderType				shaderType,
    221 	VkFormat				bufferFormat)
    222 	: vkt::TestCase(testContext, name, description)
    223 	, m_shaderStage(shaderStage)
    224 	, m_shaderType(shaderType)
    225 	, m_bufferFormat(bufferFormat)
    226 {
    227 	DE_ASSERT(m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT || m_shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT || m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT);
    228 }
    229 
    230 // A subclass for testing reading with variable pointers
    231 class RobustReadTest : public RobustAccessWithPointersTest
    232 {
    233 public:
    234 								RobustReadTest					(tcu::TestContext&		testContext,
    235 																 const std::string&		name,
    236 																 const std::string&		description,
    237 																 VkShaderStageFlags		shaderStage,
    238 																 ShaderType				shaderType,
    239 																 VkFormat				bufferFormat,
    240 																 VkDeviceSize			readAccessRange,
    241 																 bool					accessOutOfBackingMemory);
    242 
    243 	virtual						~RobustReadTest					(void)
    244 	{}
    245 	virtual TestInstance*		createInstance					(Context&				context) const;
    246 private:
    247 	virtual void				initPrograms					(SourceCollections&		programCollection) const;
    248 	const VkDeviceSize			m_readAccessRange;
    249 	const bool					m_accessOutOfBackingMemory;
    250 };
    251 
    252 // A subclass for testing writing with variable pointers
    253 class RobustWriteTest : public RobustAccessWithPointersTest
    254 {
    255 public:
    256 								RobustWriteTest				(tcu::TestContext&		testContext,
    257 															 const std::string&		name,
    258 															 const std::string&		description,
    259 															 VkShaderStageFlags		shaderStage,
    260 															 ShaderType				shaderType,
    261 															 VkFormat				bufferFormat,
    262 															 VkDeviceSize			writeAccessRange,
    263 															 bool					accessOutOfBackingMemory);
    264 
    265 	virtual						~RobustWriteTest			(void) {}
    266 	virtual TestInstance*		createInstance				(Context& context) const;
    267 private:
    268 	virtual void				initPrograms				(SourceCollections&		programCollection) const;
    269 	const VkDeviceSize			m_writeAccessRange;
    270 	const bool					m_accessOutOfBackingMemory;
    271 };
    272 
    273 // In case I detect that some prerequisites are not fullfilled I am creating this lightweight dummy test instance instead of AccessInstance. Should be bit faster that way.
    274 class NotSupportedInstance : public vkt::TestInstance
    275 {
    276 public:
    277 								NotSupportedInstance		(Context&			context,
    278 															 const std::string&	message)
    279 		: TestInstance(context)
    280 		, m_notSupportedMessage(message)
    281 	{}
    282 
    283 	virtual						~NotSupportedInstance		(void)
    284 	{
    285 	}
    286 
    287 	virtual tcu::TestStatus		iterate						(void)
    288 	{
    289 		TCU_THROW(NotSupportedError, m_notSupportedMessage.c_str());
    290 	}
    291 
    292 private:
    293 	std::string					m_notSupportedMessage;
    294 };
    295 
    296 // A superclass for instances testing reading and writing
    297 // holds all necessary object members
    298 class AccessInstance : public vkt::TestInstance
    299 {
    300 public:
    301 								AccessInstance				(Context&			context,
    302 															 Move<VkDevice>		device,
    303 															 ShaderType			shaderType,
    304 															 VkShaderStageFlags	shaderStage,
    305 															 VkFormat			bufferFormat,
    306 															 BufferAccessType	bufferAccessType,
    307 															 VkDeviceSize		inBufferAccessRange,
    308 															 VkDeviceSize		outBufferAccessRange,
    309 															 bool				accessOutOfBackingMemory);
    310 
    311 	virtual						~AccessInstance				(void) {}
    312 
    313 	virtual tcu::TestStatus		iterate						(void);
    314 
    315 	virtual bool				verifyResult				(void);
    316 
    317 private:
    318 	bool						isExpectedValueFromInBuffer	(VkDeviceSize		offsetInBytes,
    319 															 const void*		valuePtr,
    320 															 VkDeviceSize		valueSize);
    321 	bool						isOutBufferValueUnchanged	(VkDeviceSize		offsetInBytes,
    322 															 VkDeviceSize		valueSize);
    323 
    324 protected:
    325 	Move<VkDevice>				m_device;
    326 	de::MovePtr<TestEnvironment>m_testEnvironment;
    327 
    328 	const ShaderType			m_shaderType;
    329 	const VkShaderStageFlags	m_shaderStage;
    330 
    331 	const VkFormat				m_bufferFormat;
    332 	const BufferAccessType		m_bufferAccessType;
    333 
    334 	AccessRangesData			m_inBufferAccess;
    335 	Move<VkBuffer>				m_inBuffer;
    336 	de::MovePtr<Allocation>		m_inBufferAlloc;
    337 
    338 	AccessRangesData			m_outBufferAccess;
    339 	Move<VkBuffer>				m_outBuffer;
    340 	de::MovePtr<Allocation>		m_outBufferAlloc;
    341 
    342 	Move<VkBuffer>				m_indicesBuffer;
    343 	de::MovePtr<Allocation>		m_indicesBufferAlloc;
    344 
    345 	Move<VkDescriptorPool>		m_descriptorPool;
    346 	Move<VkDescriptorSetLayout>	m_descriptorSetLayout;
    347 	Move<VkDescriptorSet>		m_descriptorSet;
    348 
    349 	Move<VkFence>				m_fence;
    350 	VkQueue						m_queue;
    351 
    352 	// Used when m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT
    353 	Move<VkBuffer>				m_vertexBuffer;
    354 	de::MovePtr<Allocation>		m_vertexBufferAlloc;
    355 
    356 	const bool					m_accessOutOfBackingMemory;
    357 };
    358 
    359 // A subclass for read tests
    360 class ReadInstance: public AccessInstance
    361 {
    362 public:
    363 								ReadInstance			(Context&				context,
    364 														 Move<VkDevice>			device,
    365 														 ShaderType				shaderType,
    366 														 VkShaderStageFlags		shaderStage,
    367 														 VkFormat				bufferFormat,
    368 														 VkDeviceSize			inBufferAccessRange,
    369 														 bool					accessOutOfBackingMemory);
    370 
    371 	virtual						~ReadInstance			(void) {}
    372 };
    373 
    374 // A subclass for write tests
    375 class WriteInstance: public AccessInstance
    376 {
    377 public:
    378 								WriteInstance			(Context&				context,
    379 														 Move<VkDevice>			device,
    380 														 ShaderType				shaderType,
    381 														 VkShaderStageFlags		shaderStage,
    382 														 VkFormat				bufferFormat,
    383 														 VkDeviceSize			writeBufferAccessRange,
    384 														 bool					accessOutOfBackingMemory);
    385 
    386 	virtual						~WriteInstance			(void) {}
    387 };
    388 
    389 // Automatically incremented counter.
    390 // Each read of value bumps counter up.
    391 class Autocounter
    392 {
    393 public:
    394 								Autocounter()
    395 		:value(0u)
    396 	{}
    397 	deUint32					incrementAndGetValue()
    398 	{
    399 		return ++value;
    400 	}
    401 private:
    402 	deUint32					value;
    403 };
    404 
    405 // A class representing SPIRV variable.
    406 // This class internally has an unique identificator.
    407 // When such variable is used in shader composition routine it is mapped on a in-SPIRV-code variable name.
    408 class Variable
    409 {
    410 	friend bool					operator < (const Variable& a, const Variable& b);
    411 public:
    412 								Variable(Autocounter& autoincrement)
    413 		: value(autoincrement.incrementAndGetValue())
    414 	{}
    415 private:
    416 	deUint32					value;
    417 };
    418 
    419 bool operator < (const Variable& a, const Variable& b)
    420 {
    421 	return a.value < b.value;
    422 }
    423 
    424 // A class representing SPIRV operation.
    425 // Since those are not copyable they don't need internal id. Memory address is used instead.
    426 class Operation
    427 {
    428 	friend bool					operator==(const Operation& a, const Operation& b);
    429 public:
    430 								Operation(const char* text)
    431 		: value(text)
    432 	{
    433 	}
    434 	const std::string&			getValue() const
    435 	{
    436 		return value;
    437 	}
    438 
    439 private:
    440 								Operation(const Operation& other);
    441 	const std::string			value;
    442 };
    443 
    444 bool operator == (const Operation& a, const Operation& b)
    445 {
    446 	return &a == &b; // a fast & simple address comparison - making copies was disabled
    447 }
    448 
    449 // A namespace containing all SPIRV operations used in those tests.
    450 namespace op {
    451 #define OP(name) const Operation name("Op"#name)
    452 	OP(Capability);
    453 	OP(Extension);
    454 	OP(ExtInstImport);
    455 	OP(EntryPoint);
    456 	OP(MemoryModel);
    457 	OP(ExecutionMode);
    458 
    459 	OP(Decorate);
    460 	OP(MemberDecorate);
    461 	OP(Name);
    462 	OP(MemberName);
    463 
    464 	OP(TypeVoid);
    465 	OP(TypeBool);
    466 	OP(TypeInt);
    467 	OP(TypeFloat);
    468 	OP(TypeVector);
    469 	OP(TypeMatrix);
    470 	OP(TypeArray);
    471 	OP(TypeStruct);
    472 	OP(TypeFunction);
    473 	OP(TypePointer);
    474 	OP(TypeImage);
    475 	OP(TypeSampledImage);
    476 
    477 	OP(Constant);
    478 	OP(ConstantComposite);
    479 	OP(Variable);
    480 
    481 	OP(Function);
    482 	OP(FunctionEnd);
    483 	OP(Label);
    484 	OP(Return);
    485 
    486 	OP(LogicalEqual);
    487 	OP(IEqual);
    488 	OP(Select);
    489 
    490 	OP(AccessChain);
    491 	OP(Load);
    492 	OP(Store);
    493 #undef OP
    494 }
    495 
    496 // A class that allows to easily compose SPIRV code.
    497 // This class automatically keeps correct order of most of operations
    498 // i.e. capabilities to the top,
    499 class ShaderStream
    500 {
    501 public:
    502 								ShaderStream ()
    503 	{}
    504 	// composes shader string out of shader substreams.
    505 	std::string					str () const
    506 	{
    507 		std::stringstream stream;
    508 		stream << capabilities.str()
    509 			<< "; ----------------- PREAMBLE -----------------\n"
    510 			<< preamble.str()
    511 			<< "; ----------------- DEBUG --------------------\n"
    512 			<< names.str()
    513 			<< "; ----------------- DECORATIONS --------------\n"
    514 			<< decorations.str()
    515 			<< "; ----------------- TYPES --------------------\n"
    516 			<< basictypes.str()
    517 			<< "; ----------------- CONSTANTS ----------------\n"
    518 			<< constants.str()
    519 			<< "; ----------------- ADVANCED TYPES -----------\n"
    520 			<< compositetypes.str()
    521 			<< ((compositeconstants.str().length() > 0) ? "; ----------------- CONSTANTS ----------------\n" : "")
    522 			<< compositeconstants.str()
    523 			<< "; ----------------- VARIABLES & FUNCTIONS ----\n"
    524 			<< shaderstream.str();
    525 		return stream.str();
    526 	}
    527 	// Functions below are used to push Operations, Variables and other strings, numbers and characters to the shader.
    528 	// Each function uses selectStream and map subroutines.
    529 	// selectStream is used to choose a proper substream of shader.
    530 	// E.g. if an operation is OpConstant it should be put into constants definitions stream - so selectStream will return that stream.
    531 	// map on the other hand is used to replace Variables and Operations to their in-SPIRV-code representations.
    532 	// for types like ints or floats map simply calls << operator to produce its string representation
    533 	// for Operations a proper operation string is returned
    534 	// for Variables there is a special mapping between in-C++ variable and in-SPIRV-code variable name.
    535 	// following sequence of functions could be squashed to just two using variadic templates once we move to C++11 or higher
    536 	// each method returns *this to allow chaining calls to these methods.
    537 	template <typename T>
    538 	ShaderStream&				operator () (const T& a)
    539 	{
    540 		selectStream(a, 0) << map(a) << '\n';
    541 		return *this;
    542 	}
    543 	template <typename T1, typename T2>
    544 	ShaderStream&				operator () (const T1& a, const T2& b)
    545 	{
    546 		selectStream(a, 0) << map(a) << '\t' << map(b) << '\n';
    547 		return *this;
    548 	}
    549 	template <typename T1, typename T2, typename T3>
    550 	ShaderStream&				operator () (const T1& a, const T2& b, const T3& c)
    551 	{
    552 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\n';
    553 		return *this;
    554 	}
    555 	template <typename T1, typename T2, typename T3, typename T4>
    556 	ShaderStream&				operator () (const T1& a, const T2& b, const T3& c, const T4& d)
    557 	{
    558 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\n';
    559 		return *this;
    560 	}
    561 	template <typename T1, typename T2, typename T3, typename T4, typename T5>
    562 	ShaderStream&				operator () (const T1& a, const T2& b, const T3& c, const T4& d, const T5& e)
    563 	{
    564 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\n';
    565 		return *this;
    566 	}
    567 	template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    568 	ShaderStream&				operator () (const T1& a, const T2& b, const T3& c, const T4& d, const T5& e, const T6& f)
    569 	{
    570 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\t' << map(f) << '\n';
    571 		return *this;
    572 	}
    573 	template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
    574 	ShaderStream&				operator () (const T1& a, const T2& b, const  T3& c, const T4& d, const T5& e, const T6& f, const T7& g)
    575 	{
    576 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\t' << map(f) << '\t' << map(g) << '\n';
    577 		return *this;
    578 	}
    579 	template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
    580 	ShaderStream&				operator () (const T1& a, const T2& b, const  T3& c, const T4& d, const T5& e, const T6& f, const T7& g, const T8& h)
    581 	{
    582 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\t' << map(f) << '\t' << map(g) << '\t' << map(h) << '\n';
    583 		return *this;
    584 	}
    585 	template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
    586 	ShaderStream&				operator () (const T1& a, const T2& b, const  T3& c, const T4& d, const T5& e, const T6& f, const T7& g, const T8& h, const T9& i)
    587 	{
    588 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\t' << map(f) << '\t' << map(g) << '\t' << map(h) << '\t' << map(i) << '\n';
    589 		return *this;
    590 	}
    591 	template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
    592 	ShaderStream&				operator () (const T1& a, const T2& b, const  T3& c, const T4& d, const T5& e, const T6& f, const T7& g, const T8& h, const T9& i, const T10& k)
    593 	{
    594 		selectStream(a, c) << map(a) << '\t' << map(b) << '\t' << map(c) << '\t' << map(d) << '\t' << map(e) << '\t' << map(f) << '\t' << map(g) << '\t' << map(h) << '\t' << map(i) << '\t' << map(k) << '\n';
    595 		return *this;
    596 	}
    597 
    598 	// returns true if two variables has the same in-SPIRV-code names
    599 	bool						areSame (const Variable a, const Variable b)
    600 	{
    601 		VariableIt varA = vars.find(a);
    602 		VariableIt varB = vars.find(b);
    603 		return varA != vars.end() && varB != vars.end() && varA->second == varB->second;
    604 	}
    605 
    606 	// makes variable 'a' in-SPIRV-code name to be the same as variable 'b' in-SPIRV-code name
    607 	void						makeSame (const Variable a, const Variable b)
    608 	{
    609 		VariableIt varB = vars.find(b);
    610 		if (varB != vars.end())
    611 		{
    612 			std::pair<VariableIt, bool> inserted = vars.insert(std::make_pair(a, varB->second));
    613 			if (!inserted.second)
    614 				inserted.first->second = varB->second;
    615 		}
    616 	}
    617 private:
    618 	// generic version of map (tries to push whatever came to stringstream to get its string representation)
    619 	template <typename T>
    620 	std::string					map (const T& a)
    621 	{
    622 		std::stringstream temp;
    623 		temp << a;
    624 		return temp.str();
    625 	}
    626 
    627 	// looks for mapping of c++ Variable object onto in-SPIRV-code name.
    628 	// if there was not yet such mapping generated a new mapping is created based on incremented local counter.
    629 	std::string					map (const Variable& a)
    630 	{
    631 		VariableIt var = vars.find(a);
    632 		if (var != vars.end())
    633 			return var->second;
    634 		std::stringstream temp;
    635 		temp << '%';
    636 		temp.width(4);
    637 		temp.fill('0');
    638 		temp << std::hex << varCounter.incrementAndGetValue();
    639 		vars.insert(std::make_pair(a, temp.str()));
    640 		return temp.str();
    641 	}
    642 
    643 	// a simple specification for Operation
    644 	std::string					map (const Operation& a)
    645 	{
    646 		return a.getValue();
    647 	}
    648 
    649 	// a specification for char* - faster than going through stringstream << operator
    650 	std::string					map (const char*& a)
    651 	{
    652 		return std::string(a);
    653 	}
    654 
    655 	// a specification for char - faster than going through stringstream << operator
    656 	std::string					map (const char& a)
    657 	{
    658 		return std::string(1, a);
    659 	}
    660 
    661 	// a generic version of selectStream - used when neither 1st nor 3rd SPIRV line token is Operation.
    662 	// In general should never happen.
    663 	// All SPIRV lines are constructed in a one of two forms:
    664 	// Variable = Operation operands...
    665 	// or
    666 	// Operation operands...
    667 	// So operation is either 1st or 3rd token.
    668 	template <typename T0, typename T1>
    669 	std::stringstream&			selectStream (const T0& op0, const T1& op1)
    670 	{
    671 		DE_UNREF(op0);
    672 		DE_UNREF(op1);
    673 		return shaderstream;
    674 	}
    675 
    676 	// Specialisation for Operation being 1st parameter
    677 	// Certain operations make the SPIRV code line to be pushed to different substreams.
    678 	template <typename T1>
    679 	std::stringstream&			selectStream (const Operation& op, const T1& op1)
    680 	{
    681 		DE_UNREF(op1);
    682 		if (op == op::Decorate || op == op::MemberDecorate)
    683 			return decorations;
    684 		if (op == op::Name || op == op::MemberName)
    685 			return names;
    686 		if (op == op::Capability || op == op::Extension)
    687 			return capabilities;
    688 		if (op == op::MemoryModel || op == op::ExecutionMode || op == op::EntryPoint)
    689 			return preamble;
    690 		return shaderstream;
    691 	}
    692 
    693 	// Specialisation for Operation being 3rd parameter
    694 	// Certain operations make the SPIRV code line to be pushed to different substreams.
    695 	// If we would like to use this way of generating SPIRV we could use this method as SPIRV line validation point
    696 	// e.g. here instead of heving partial specialisation I could specialise for T0 being Variable since this has to match Variable = Operation operands...
    697 	template <typename T0>
    698 	std::stringstream&			selectStream (const T0& op0, const Operation& op)
    699 	{
    700 		DE_UNREF(op0);
    701 		if (op == op::ExtInstImport)
    702 			return preamble;
    703 		if (op == op::TypeVoid || op == op::TypeBool || op == op::TypeInt || op == op::TypeFloat || op == op::TypeVector || op == op::TypeMatrix)
    704 			return basictypes;
    705 		if (op == op::TypeArray || op == op::TypeStruct || op == op::TypeFunction || op == op::TypePointer || op == op::TypeImage || op == op::TypeSampledImage)
    706 			return compositetypes;
    707 		if (op == op::Constant)
    708 			return constants;
    709 		if (op == op::ConstantComposite)
    710 			return compositeconstants;
    711 		return shaderstream;
    712 	}
    713 
    714 	typedef std::map<Variable, std::string>	VariablesPack;
    715 	typedef VariablesPack::iterator			VariableIt;
    716 
    717 	// local mappings between c++ Variable objects and in-SPIRV-code names
    718 	VariablesPack				vars;
    719 
    720 	// shader substreams
    721 	std::stringstream			capabilities;
    722 	std::stringstream			preamble;
    723 	std::stringstream			names;
    724 	std::stringstream			decorations;
    725 	std::stringstream			basictypes;
    726 	std::stringstream			constants;
    727 	std::stringstream			compositetypes;
    728 	std::stringstream			compositeconstants;
    729 	std::stringstream			shaderstream;
    730 
    731 	// local incremented counter
    732 	Autocounter					varCounter;
    733 };
    734 
    735 // A suppliementary class to group frequently used Variables together
    736 class Variables
    737 {
    738 public:
    739 								Variables (Autocounter &autoincrement)
    740 		: version(autoincrement)
    741 		, mainFunc(autoincrement)
    742 		, mainFuncLabel(autoincrement)
    743 		, voidFuncVoid(autoincrement)
    744 		, copy_type(autoincrement)
    745 		, copy_type_vec(autoincrement)
    746 		, buffer_type_vec(autoincrement)
    747 		, copy_type_ptr(autoincrement)
    748 		, buffer_type(autoincrement)
    749 		, voidId(autoincrement)
    750 		, v4f32(autoincrement)
    751 		, v4s32(autoincrement)
    752 		, v4u32(autoincrement)
    753 		, s32(autoincrement)
    754 		, f32(autoincrement)
    755 		, u32(autoincrement)
    756 		, boolean(autoincrement)
    757 		, array_content_type(autoincrement)
    758 		, s32_type_ptr(autoincrement)
    759 		, dataSelectorStructPtrType(autoincrement)
    760 		, dataSelectorStructPtr(autoincrement)
    761 		, dataArrayType(autoincrement)
    762 		, dataInput(autoincrement)
    763 		, dataInputPtrType(autoincrement)
    764 		, dataInputType(autoincrement)
    765 		, dataInputSampledType(autoincrement)
    766 		, dataOutput(autoincrement)
    767 		, dataOutputPtrType(autoincrement)
    768 		, dataOutputType(autoincrement)
    769 		, dataSelectorStructType(autoincrement)
    770 		, input(autoincrement)
    771 		, inputPtr(autoincrement)
    772 		, output(autoincrement)
    773 		, outputPtr(autoincrement)
    774 	{
    775 		for (deUint32 i = 0; i < 32; ++i)
    776 			constants.push_back(Variable(autoincrement));
    777 	}
    778 	const Variable				version;
    779 	const Variable				mainFunc;
    780 	const Variable				mainFuncLabel;
    781 	const Variable				voidFuncVoid;
    782 	std::vector<Variable>		constants;
    783 	const Variable				copy_type;
    784 	const Variable				copy_type_vec;
    785 	const Variable				buffer_type_vec;
    786 	const Variable				copy_type_ptr;
    787 	const Variable				buffer_type;
    788 	const Variable				voidId;
    789 	const Variable				v4f32;
    790 	const Variable				v4s32;
    791 	const Variable				v4u32;
    792 	const Variable				s32;
    793 	const Variable				f32;
    794 	const Variable				u32;
    795 	const Variable				boolean;
    796 	const Variable				array_content_type;
    797 	const Variable				s32_type_ptr;
    798 	const Variable				dataSelectorStructPtrType;
    799 	const Variable				dataSelectorStructPtr;
    800 	const Variable				dataArrayType;
    801 	const Variable				dataInput;
    802 	const Variable				dataInputPtrType;
    803 	const Variable				dataInputType;
    804 	const Variable				dataInputSampledType;
    805 	const Variable				dataOutput;
    806 	const Variable				dataOutputPtrType;
    807 	const Variable				dataOutputType;
    808 	const Variable				dataSelectorStructType;
    809 	const Variable				input;
    810 	const Variable				inputPtr;
    811 	const Variable				output;
    812 	const Variable				outputPtr;
    813 };
    814 
    815 // A routing generating SPIRV code for all test cases in this group
    816 std::string MakeShader(VkShaderStageFlags shaderStage, ShaderType shaderType, VkFormat bufferFormat, bool reads, bool dummy)
    817 {
    818 	// faster to write
    819 	const char					is					= '=';
    820 
    821 	// variables require such counter to generate their unique ids. Since there is possibility that in the future this code will
    822 	// run parallel this counter is made local to this function body to be safe.
    823 	Autocounter					localcounter;
    824 
    825 	// A frequently used Variables (gathered into this single object for readability)
    826 	Variables					var					(localcounter);
    827 
    828 	// A SPIRV code builder
    829 	ShaderStream				shaderSource;
    830 
    831 	// A basic preamble of SPIRV shader. Turns on required capabilities and extensions.
    832 	shaderSource
    833 	(op::Capability, "Shader")
    834 	(op::Capability, "VariablePointersStorageBuffer")
    835 	(op::Extension, "\"SPV_KHR_storage_buffer_storage_class\"")
    836 	(op::Extension, "\"SPV_KHR_variable_pointers\"")
    837 	(var.version, is, op::ExtInstImport, "\"GLSL.std.450\"")
    838 	(op::MemoryModel, "Logical", "GLSL450");
    839 
    840 	// Use correct entry point definition depending on shader stage
    841 	if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
    842 	{
    843 		shaderSource
    844 		(op::EntryPoint, "GLCompute", var.mainFunc, "\"main\"")
    845 		(op::ExecutionMode, var.mainFunc, "LocalSize", 1, 1, 1);
    846 	}
    847 	else if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
    848 	{
    849 		shaderSource
    850 		(op::EntryPoint, "Vertex", var.mainFunc, "\"main\"", var.input, var.output)
    851 		(op::Decorate, var.output, "BuiltIn", "Position")
    852 		(op::Decorate, var.input, "Location", 0);
    853 	}
    854 	else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
    855 	{
    856 		shaderSource
    857 		(op::EntryPoint, "Fragment", var.mainFunc, "\"main\"", var.output)
    858 		(op::ExecutionMode, var.mainFunc, "OriginUpperLeft")
    859 		(op::Decorate, var.output, "Location", 0);
    860 	}
    861 
    862 	// If we are testing vertex shader or fragment shader we need to provide the other one for the pipeline too.
    863 	// So the not tested one is 'dummy'. It is then a minimal/simplest possible pass-through shader.
    864 	// If we are testing compute shader we dont need dummy shader at all.
    865 	if (dummy)
    866 	{
    867 		if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
    868 		{
    869 			shaderSource
    870 			(var.voidId, is, op::TypeVoid)
    871 			(var.voidFuncVoid, is, op::TypeFunction, var.voidId)
    872 			(var.f32, is, op::TypeFloat, 32)
    873 			(var.v4f32, is, op::TypeVector, var.f32, 4)
    874 			(var.outputPtr, is, op::TypePointer, "Output", var.v4f32)
    875 			(var.output, is, op::Variable, var.outputPtr, "Output")
    876 			(var.constants[6], is, op::Constant, var.f32, 1)
    877 			(var.constants[7], is, op::ConstantComposite, var.v4f32, var.constants[6], var.constants[6], var.constants[6], var.constants[6])
    878 			(var.mainFunc, is, op::Function, var.voidId, "None", var.voidFuncVoid)
    879 			(var.mainFuncLabel, is, op::Label);
    880 		}
    881 		else if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
    882 		{
    883 			shaderSource
    884 			(var.voidId, is, op::TypeVoid)
    885 			(var.voidFuncVoid, is, op::TypeFunction , var.voidId)
    886 			(var.f32, is, op::TypeFloat, 32)
    887 			(var.v4f32, is, op::TypeVector , var.f32, 4)
    888 			(var.outputPtr, is, op::TypePointer, "Output" , var.v4f32)
    889 			(var.output, is, op::Variable , var.outputPtr, "Output")
    890 			(var.inputPtr, is, op::TypePointer, "Input" , var.v4f32)
    891 			(var.input, is, op::Variable , var.inputPtr, "Input")
    892 			(var.mainFunc, is, op::Function , var.voidId, "None", var.voidFuncVoid)
    893 			(var.mainFuncLabel, is, op::Label);
    894 		}
    895 	}
    896 	else // this is a start of actual shader that tests variable pointers
    897 	{
    898 		shaderSource
    899 		(op::Decorate, var.dataInput, "DescriptorSet", 0)
    900 		(op::Decorate, var.dataInput, "Binding", 0)
    901 
    902 		(op::Decorate, var.dataOutput, "DescriptorSet", 0)
    903 		(op::Decorate, var.dataOutput, "Binding", 1);
    904 
    905 		// for scalar types and vector types we use 1024 element array of 4 elements arrays of 4-component vectors
    906 		// so the stride of internal array is size of 4-component vector
    907 		if (shaderType == SHADER_TYPE_SCALAR_COPY || shaderType == SHADER_TYPE_VECTOR_COPY)
    908 		{
    909 			shaderSource
    910 			(op::Decorate, var.array_content_type, "ArrayStride", 16);
    911 		}
    912 		// for matrices we use array of 4x4-component matrices
    913 		// stride of outer array is then 64 in every case
    914 		shaderSource
    915 		(op::Decorate, var.dataArrayType, "ArrayStride", 64)
    916 
    917 		// an output block
    918 		(op::MemberDecorate, var.dataOutputType, 0, "Offset", 0)
    919 		(op::Decorate, var.dataOutputType, "Block")
    920 
    921 		// an input block. Marked readonly.
    922 		(op::MemberDecorate, var.dataInputType, 0, "NonWritable")
    923 		(op::MemberDecorate, var.dataInputType, 0, "Offset", 0)
    924 		(op::Decorate, var.dataInputType, "Block")
    925 
    926 		//a special structure matching data in one of our buffers.
    927 		// member at 0 is an index to read position
    928 		// member at 1 is an index to write position
    929 		// member at 2 is always zero. It is used to perform OpSelect. I used value coming from buffer to avoid incidental optimisations that could prune OpSelect if the value was compile time known.
    930 		(op::MemberDecorate, var.dataSelectorStructType, 0, "Offset", 0)
    931 		(op::MemberDecorate, var.dataSelectorStructType, 1, "Offset", 4)
    932 		(op::MemberDecorate, var.dataSelectorStructType, 2, "Offset", 8)
    933 		(op::Decorate, var.dataSelectorStructType, "Block")
    934 
    935 		// binding to matching buffer
    936 		(op::Decorate, var.dataSelectorStructPtr, "DescriptorSet", 0)
    937 		(op::Decorate, var.dataSelectorStructPtr, "Binding", 2)
    938 
    939 		// making composite types used in shader
    940 		(var.voidId, is, op::TypeVoid)
    941 		(var.voidFuncVoid, is, op::TypeFunction, var.voidId)
    942 
    943 		(var.boolean, is, op::TypeBool)
    944 
    945 		(var.f32, is, op::TypeFloat, 32)
    946 		(var.s32, is, op::TypeInt, 32, 1)
    947 		(var.u32, is, op::TypeInt, 32, 0)
    948 
    949 		(var.v4f32, is, op::TypeVector, var.f32, 4)
    950 		(var.v4s32, is, op::TypeVector, var.s32, 4)
    951 		(var.v4u32, is, op::TypeVector, var.u32, 4);
    952 
    953 		// since the shared tests scalars, vectors, matrices of ints, uints and floats I am generating alternative names for some of the types so I can use those and not need to use "if" everywhere.
    954 		// A Variable mappings will make sure the proper variable name is used
    955 		// below is a first part of aliasing types based on int, uint, float
    956 		switch (bufferFormat)
    957 		{
    958 		case vk::VK_FORMAT_R32_SINT:
    959 			shaderSource.makeSame(var.buffer_type, var.s32);
    960 			shaderSource.makeSame(var.buffer_type_vec, var.v4s32);
    961 			break;
    962 		case vk::VK_FORMAT_R32_UINT:
    963 			shaderSource.makeSame(var.buffer_type, var.u32);
    964 			shaderSource.makeSame(var.buffer_type_vec, var.v4u32);
    965 			break;
    966 		case vk::VK_FORMAT_R32_SFLOAT:
    967 			shaderSource.makeSame(var.buffer_type, var.f32);
    968 			shaderSource.makeSame(var.buffer_type_vec, var.v4f32);
    969 			break;
    970 		default:
    971 			// to prevent compiler from complaining not all cases are handled (but we should not get here).
    972 			deAssertFail("This point should be not reachable with correct program flow.", __FILE__, __LINE__);
    973 			break;
    974 		}
    975 
    976 		// below is a second part that aliases based on scalar, vector, matrix
    977 		switch (shaderType)
    978 		{
    979 		case SHADER_TYPE_SCALAR_COPY:
    980 			shaderSource.makeSame(var.copy_type, var.buffer_type);
    981 			break;
    982 		case SHADER_TYPE_VECTOR_COPY:
    983 			shaderSource.makeSame(var.copy_type, var.buffer_type_vec);
    984 			break;
    985 		case SHADER_TYPE_MATRIX_COPY:
    986 			if (bufferFormat != VK_FORMAT_R32_SFLOAT)
    987 				TCU_THROW(NotSupportedError, "Matrices can be used only with floating point types.");
    988 			shaderSource
    989 			(var.copy_type, is, op::TypeMatrix, var.buffer_type_vec, 4);
    990 			break;
    991 		default:
    992 			// to prevent compiler from complaining not all cases are handled (but we should not get here).
    993 			deAssertFail("This point should be not reachable with correct program flow.", __FILE__, __LINE__);
    994 			break;
    995 		}
    996 
    997 		// I will need some constants so lets add them to shader source
    998 		shaderSource
    999 		(var.constants[0], is, op::Constant, var.s32, 0)
   1000 		(var.constants[1], is, op::Constant, var.s32, 1)
   1001 		(var.constants[2], is, op::Constant, var.s32, 2)
   1002 		(var.constants[3], is, op::Constant, var.s32, 3)
   1003 		(var.constants[4], is, op::Constant, var.u32, 4)
   1004 		(var.constants[5], is, op::Constant, var.u32, 1024);
   1005 
   1006 		// for fragment shaders I need additionally a constant vector (output "colour") so lets make it
   1007 		if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
   1008 		{
   1009 			shaderSource
   1010 			(var.constants[6], is, op::Constant, var.f32, 1)
   1011 			(var.constants[7], is, op::ConstantComposite, var.v4f32, var.constants[6], var.constants[6], var.constants[6], var.constants[6]);
   1012 		}
   1013 
   1014 		// additional alias for the type of content of this 1024-element outer array.
   1015 		if (shaderType == SHADER_TYPE_SCALAR_COPY || shaderType == SHADER_TYPE_VECTOR_COPY)
   1016 		{
   1017 			shaderSource
   1018 			(var.array_content_type, is, op::TypeArray, var.buffer_type_vec, var.constants[4]);
   1019 		}
   1020 		else
   1021 		{
   1022 			shaderSource.makeSame(var.array_content_type, var.copy_type);
   1023 		}
   1024 
   1025 		// Lets create pointer types to the input data type, output data type and a struct
   1026 		// This must be distinct types due to different type decorations
   1027 		// Lets make also actual poiters to the data
   1028 		shaderSource
   1029 		(var.dataArrayType, is, op::TypeArray, var.array_content_type, var.constants[5])
   1030 		(var.dataInputType, is, op::TypeStruct, var.dataArrayType)
   1031 		(var.dataOutputType, is, op::TypeStruct, var.dataArrayType)
   1032 		(var.dataInputPtrType, is, op::TypePointer, "StorageBuffer", var.dataInputType)
   1033 		(var.dataOutputPtrType, is, op::TypePointer, "StorageBuffer", var.dataOutputType)
   1034 		(var.dataInput, is, op::Variable, var.dataInputPtrType, "StorageBuffer")
   1035 		(var.dataOutput, is, op::Variable, var.dataOutputPtrType, "StorageBuffer")
   1036 		(var.dataSelectorStructType, is, op::TypeStruct, var.s32, var.s32, var.s32)
   1037 		(var.dataSelectorStructPtrType, is, op::TypePointer, "Uniform", var.dataSelectorStructType)
   1038 		(var.dataSelectorStructPtr, is, op::Variable, var.dataSelectorStructPtrType, "Uniform");
   1039 
   1040 		// we need also additional pointers to fullfil stage requirements on shaders inputs and outputs
   1041 		if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
   1042 		{
   1043 			shaderSource
   1044 			(var.inputPtr, is, op::TypePointer, "Input", var.v4f32)
   1045 			(var.input, is, op::Variable, var.inputPtr, "Input")
   1046 			(var.outputPtr, is, op::TypePointer, "Output", var.v4f32)
   1047 			(var.output, is, op::Variable, var.outputPtr, "Output");
   1048 		}
   1049 		else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
   1050 		{
   1051 			shaderSource
   1052 			(var.outputPtr, is, op::TypePointer, "Output", var.v4f32)
   1053 			(var.output, is, op::Variable, var.outputPtr, "Output");
   1054 		}
   1055 
   1056 		shaderSource
   1057 		(var.copy_type_ptr, is, op::TypePointer, "StorageBuffer", var.copy_type)
   1058 		(var.s32_type_ptr, is, op::TypePointer, "Uniform", var.s32);
   1059 
   1060 		// Make a shader main function
   1061 		shaderSource
   1062 		(var.mainFunc, is, op::Function, var.voidId, "None", var.voidFuncVoid)
   1063 		(var.mainFuncLabel, is, op::Label);
   1064 
   1065 		Variable copyFromPtr(localcounter), copyToPtr(localcounter), zeroPtr(localcounter);
   1066 		Variable copyFrom(localcounter), copyTo(localcounter), zero(localcounter);
   1067 
   1068 		// Lets load data from our auxiliary buffer with reading index, writing index and zero.
   1069 		shaderSource
   1070 		(copyToPtr, is, op::AccessChain, var.s32_type_ptr, var.dataSelectorStructPtr, var.constants[1])
   1071 		(copyTo, is, op::Load, var.s32, copyToPtr)
   1072 		(copyFromPtr, is, op::AccessChain, var.s32_type_ptr, var.dataSelectorStructPtr, var.constants[0])
   1073 		(copyFrom, is, op::Load, var.s32, copyFromPtr)
   1074 		(zeroPtr, is, op::AccessChain, var.s32_type_ptr, var.dataSelectorStructPtr, var.constants[2])
   1075 		(zero, is, op::Load, var.s32, zeroPtr);
   1076 
   1077 		// let start copying data using variable pointers
   1078 		switch (shaderType)
   1079 		{
   1080 		case SHADER_TYPE_SCALAR_COPY:
   1081 			for (int i = 0; i < 4; ++i)
   1082 			{
   1083 				for (int j = 0; j < 4; ++j)
   1084 				{
   1085 					Variable actualLoadChain(localcounter), actualStoreChain(localcounter), loadResult(localcounter);
   1086 					Variable selection(localcounter);
   1087 					Variable lcA(localcounter), lcB(localcounter), scA(localcounter), scB(localcounter);
   1088 
   1089 					shaderSource
   1090 					(selection, is, op::IEqual, var.boolean, zero, var.constants[0]);
   1091 
   1092 					if (reads)
   1093 					{
   1094 						// if we check reads we use variable pointers only for reading part
   1095 						shaderSource
   1096 						(lcA, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i], var.constants[j])
   1097 						(lcB, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i], var.constants[j])
   1098 						// actualLoadChain will be a variable pointer as it was created through OpSelect
   1099 						(actualLoadChain, is, op::Select, var.copy_type_ptr, selection, lcA, lcB)
   1100 						// actualStoreChain will be a regular pointer
   1101 						(actualStoreChain, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i], var.constants[j]);
   1102 					}
   1103 					else
   1104 					{
   1105 						// if we check writes we use variable pointers only for writing part only
   1106 						shaderSource
   1107 						// actualLoadChain will be regular regualar pointer
   1108 						(actualLoadChain, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i], var.constants[j])
   1109 						(scA, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i], var.constants[j])
   1110 						(scB, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i], var.constants[j])
   1111 						// actualStoreChain will be a variable pointer as it was created through OpSelect
   1112 						(actualStoreChain, is, op::Select, var.copy_type_ptr, selection, scA, scB);
   1113 					}
   1114 					// do actual copying
   1115 					shaderSource
   1116 					(loadResult, is, op::Load, var.copy_type, actualLoadChain)
   1117 					(op::Store, actualStoreChain, loadResult);
   1118 				}
   1119 			}
   1120 			break;
   1121 		// cases below have the same logic as the one above - just we are copying bigger chunks of data with every load/store pair
   1122 		case SHADER_TYPE_VECTOR_COPY:
   1123 			for (int i = 0; i < 4; ++i)
   1124 			{
   1125 				Variable actualLoadChain(localcounter), actualStoreChain(localcounter), loadResult(localcounter);
   1126 				Variable selection(localcounter);
   1127 				Variable lcA(localcounter), lcB(localcounter), scA(localcounter), scB(localcounter);
   1128 
   1129 				shaderSource
   1130 				(selection, is, op::IEqual, var.boolean, zero, var.constants[0]);
   1131 
   1132 				if (reads)
   1133 				{
   1134 					shaderSource
   1135 					(lcA, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i])
   1136 					(lcB, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i])
   1137 					(actualLoadChain, is, op::Select, var.copy_type_ptr, selection, lcA, lcB)
   1138 					(actualStoreChain, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i]);
   1139 				}
   1140 				else
   1141 				{
   1142 					shaderSource
   1143 					(actualLoadChain, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom, var.constants[i])
   1144 					(scA, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i])
   1145 					(scB, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo, var.constants[i])
   1146 					(actualStoreChain, is, op::Select, var.copy_type_ptr, selection, scA, scB);
   1147 				}
   1148 
   1149 				shaderSource
   1150 				(loadResult, is, op::Load, var.copy_type, actualLoadChain)
   1151 				(op::Store, actualStoreChain, loadResult);
   1152 			}
   1153 			break;
   1154 		case SHADER_TYPE_MATRIX_COPY:
   1155 			{
   1156 				Variable actualLoadChain(localcounter), actualStoreChain(localcounter), loadResult(localcounter);
   1157 				Variable selection(localcounter);
   1158 				Variable lcA(localcounter), lcB(localcounter), scA(localcounter), scB(localcounter);
   1159 
   1160 				shaderSource
   1161 				(selection, is, op::IEqual, var.boolean, zero, var.constants[0]);
   1162 
   1163 				if (reads)
   1164 				{
   1165 					shaderSource
   1166 					(lcA, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom)
   1167 					(lcB, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom)
   1168 					(actualLoadChain, is, op::Select, var.copy_type_ptr, selection, lcA, lcB)
   1169 					(actualStoreChain, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo);
   1170 				}
   1171 				else
   1172 				{
   1173 					shaderSource
   1174 					(actualLoadChain, is, op::AccessChain, var.copy_type_ptr, var.dataInput, var.constants[0], copyFrom)
   1175 					(scA, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo)
   1176 					(scB, is, op::AccessChain, var.copy_type_ptr, var.dataOutput, var.constants[0], copyTo)
   1177 					(actualStoreChain, is, op::Select, var.copy_type_ptr, selection, scA, scB);
   1178 				}
   1179 
   1180 				shaderSource
   1181 				(loadResult, is, op::Load, var.copy_type, actualLoadChain)
   1182 				(op::Store, actualStoreChain, loadResult);
   1183 			}
   1184 			break;
   1185 		default:
   1186 			// to prevent compiler from complaining not all cases are handled (but we should not get here).
   1187 			deAssertFail("This point should be not reachable with correct program flow.", __FILE__, __LINE__);
   1188 			break;
   1189 		}
   1190 	}
   1191 
   1192 	// This is common for test shaders and dummy ones
   1193 	// We need to fill stage ouput from shader properly
   1194 	// output vertices positions in vertex shader
   1195 	if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
   1196 	{
   1197 		Variable inputValue(localcounter), outputLocation(localcounter);
   1198 		shaderSource
   1199 		(inputValue, is, op::Load, var.v4f32, var.input)
   1200 		(outputLocation, is, op::AccessChain, var.outputPtr, var.output)
   1201 		(op::Store, outputLocation, inputValue);
   1202 	}
   1203 	// output colour in fragment shader
   1204 	else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
   1205 	{
   1206 		shaderSource
   1207 		(op::Store, var.output, var.constants[7]);
   1208 	}
   1209 
   1210 	// We are done. Lets close main function body
   1211 	shaderSource
   1212 	(op::Return)
   1213 	(op::FunctionEnd);
   1214 
   1215 	return shaderSource.str();
   1216 }
   1217 
   1218 RobustReadTest::RobustReadTest (tcu::TestContext&		testContext,
   1219 								const std::string&		name,
   1220 								const std::string&		description,
   1221 								VkShaderStageFlags		shaderStage,
   1222 								ShaderType				shaderType,
   1223 								VkFormat				bufferFormat,
   1224 								VkDeviceSize			readAccessRange,
   1225 								bool					accessOutOfBackingMemory)
   1226 	: RobustAccessWithPointersTest	(testContext, name, description, shaderStage, shaderType, bufferFormat)
   1227 	, m_readAccessRange				(readAccessRange)
   1228 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
   1229 {
   1230 }
   1231 
   1232 TestInstance* RobustReadTest::createInstance (Context& context) const
   1233 {
   1234 	VkPhysicalDeviceVariablePointerFeatures pointerFeatures = querySupportedVariablePointersFeatures(context.getUsedApiVersion(), context.getInstanceInterface(), context.getPhysicalDevice(), context.getInstanceExtensions());
   1235 
   1236 	if (pointerFeatures.variablePointersStorageBuffer != DE_TRUE)
   1237 		return new NotSupportedInstance(context, std::string("VariablePointersStorageBuffer support is required for this test."));
   1238 
   1239 	// We need a device with enabled robust buffer access feature (it is disabled in default device)
   1240 	Move<VkDevice>	device = createRobustBufferAccessDevice(context);
   1241 	return new ReadInstance(context, device, m_shaderType, m_shaderStage, m_bufferFormat, m_readAccessRange, m_accessOutOfBackingMemory);
   1242 }
   1243 
   1244 void RobustReadTest::initPrograms(SourceCollections&	programCollection) const
   1245 {
   1246 	if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
   1247 	{
   1248 		programCollection.spirvAsmSources.add("compute") << MakeShader(VK_SHADER_STAGE_COMPUTE_BIT, m_shaderType, m_bufferFormat, true, false);
   1249 	}
   1250 	else
   1251 	{
   1252 		programCollection.spirvAsmSources.add("vertex") << MakeShader(VK_SHADER_STAGE_VERTEX_BIT, m_shaderType, m_bufferFormat, true, m_shaderStage != VK_SHADER_STAGE_VERTEX_BIT);
   1253 		programCollection.spirvAsmSources.add("fragment") << MakeShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_shaderType, m_bufferFormat, true, m_shaderStage != VK_SHADER_STAGE_FRAGMENT_BIT);
   1254 	}
   1255 }
   1256 
   1257 RobustWriteTest::RobustWriteTest (tcu::TestContext&		testContext,
   1258 								  const std::string&	name,
   1259 								  const std::string&	description,
   1260 								  VkShaderStageFlags	shaderStage,
   1261 								  ShaderType			shaderType,
   1262 								  VkFormat				bufferFormat,
   1263 								  VkDeviceSize			writeAccessRange,
   1264 								  bool					accessOutOfBackingMemory)
   1265 
   1266 	: RobustAccessWithPointersTest	(testContext, name, description, shaderStage, shaderType, bufferFormat)
   1267 	, m_writeAccessRange			(writeAccessRange)
   1268 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
   1269 {
   1270 }
   1271 
   1272 TestInstance* RobustWriteTest::createInstance (Context& context) const
   1273 {
   1274 	VkPhysicalDeviceVariablePointerFeatures pointerFeatures = querySupportedVariablePointersFeatures(context.getUsedApiVersion(), context.getInstanceInterface(), context.getPhysicalDevice(), context.getInstanceExtensions());
   1275 	if (pointerFeatures.variablePointersStorageBuffer != DE_TRUE)
   1276 		return new NotSupportedInstance(context, std::string("VariablePointersStorageBuffer support is required for this test."));
   1277 
   1278 	// We need a device with enabled robust buffer access feature (it is disabled in default device)
   1279 	Move<VkDevice>	device = createRobustBufferAccessDevice(context);
   1280 	return new WriteInstance(context, device, m_shaderType, m_shaderStage, m_bufferFormat, m_writeAccessRange, m_accessOutOfBackingMemory);
   1281 }
   1282 
   1283 void RobustWriteTest::initPrograms(SourceCollections&	programCollection) const
   1284 {
   1285 	if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
   1286 	{
   1287 		programCollection.spirvAsmSources.add("compute") << MakeShader(VK_SHADER_STAGE_COMPUTE_BIT, m_shaderType, m_bufferFormat, false, false);
   1288 	}
   1289 	else
   1290 	{
   1291 		programCollection.spirvAsmSources.add("vertex") << MakeShader(VK_SHADER_STAGE_VERTEX_BIT, m_shaderType, m_bufferFormat, false, m_shaderStage != VK_SHADER_STAGE_VERTEX_BIT);
   1292 		programCollection.spirvAsmSources.add("fragment") << MakeShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_shaderType, m_bufferFormat, false, m_shaderStage != VK_SHADER_STAGE_FRAGMENT_BIT);
   1293 	}
   1294 }
   1295 
   1296 AccessInstance::AccessInstance (Context&			context,
   1297 								Move<VkDevice>		device,
   1298 								ShaderType			shaderType,
   1299 								VkShaderStageFlags	shaderStage,
   1300 								VkFormat			bufferFormat,
   1301 								BufferAccessType	bufferAccessType,
   1302 								VkDeviceSize		inBufferAccessRange,
   1303 								VkDeviceSize		outBufferAccessRange,
   1304 								bool				accessOutOfBackingMemory)
   1305 	: vkt::TestInstance				(context)
   1306 	, m_device						(device)
   1307 	, m_shaderType					(shaderType)
   1308 	, m_shaderStage					(shaderStage)
   1309 	, m_bufferFormat				(bufferFormat)
   1310 	, m_bufferAccessType			(bufferAccessType)
   1311 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
   1312 {
   1313 	tcu::TestLog&									log						= context.getTestContext().getLog();
   1314 	const DeviceInterface&							vk						= context.getDeviceInterface();
   1315 	const deUint32									queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
   1316 	SimpleAllocator									memAlloc				(vk, *m_device, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
   1317 
   1318 	DE_ASSERT(RobustAccessWithPointersTest::s_numberOfBytesAccessed % sizeof(deUint32) == 0);
   1319 	DE_ASSERT(inBufferAccessRange <= RobustAccessWithPointersTest::s_numberOfBytesAccessed);
   1320 	DE_ASSERT(outBufferAccessRange <= RobustAccessWithPointersTest::s_numberOfBytesAccessed);
   1321 
   1322 	// Check storage support
   1323 	if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
   1324 	{
   1325 		if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
   1326 		{
   1327 			TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
   1328 		}
   1329 	}
   1330 	else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
   1331 	{
   1332 		if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
   1333 		{
   1334 			TCU_THROW(NotSupportedError, "Stores not supported in fragment stage");
   1335 		}
   1336 	}
   1337 
   1338 	createTestBuffer(vk, *m_device, inBufferAccessRange, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, memAlloc, m_inBuffer, m_inBufferAlloc, m_inBufferAccess, &populateBufferWithValues, &m_bufferFormat);
   1339 	createTestBuffer(vk, *m_device, outBufferAccessRange, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, memAlloc, m_outBuffer, m_outBufferAlloc, m_outBufferAccess, &populateBufferWithDummy, DE_NULL);
   1340 
   1341 	deInt32 indices[] = {
   1342 		(m_accessOutOfBackingMemory && (m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE)) ? static_cast<deInt32>(RobustAccessWithPointersTest::s_testArraySize) - 1 : 0,
   1343 		(m_accessOutOfBackingMemory && (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE_TO_STORAGE)) ? static_cast<deInt32>(RobustAccessWithPointersTest::s_testArraySize) - 1 : 0,
   1344 		0
   1345 	};
   1346 	AccessRangesData indicesAccess;
   1347 	createTestBuffer(vk, *m_device, 3 * sizeof(deInt32), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, memAlloc, m_indicesBuffer, m_indicesBufferAlloc, indicesAccess, &populateBufferWithCopy, &indices);
   1348 
   1349 	log << tcu::TestLog::Message << "input  buffer - alloc size: " << m_inBufferAccess.allocSize << tcu::TestLog::EndMessage;
   1350 	log << tcu::TestLog::Message << "input  buffer - max access range: " << m_inBufferAccess.maxAccessRange << tcu::TestLog::EndMessage;
   1351 	log << tcu::TestLog::Message << "output buffer - alloc size: " << m_outBufferAccess.allocSize << tcu::TestLog::EndMessage;
   1352 	log << tcu::TestLog::Message << "output buffer - max access range: " << m_outBufferAccess.maxAccessRange << tcu::TestLog::EndMessage;
   1353 	log << tcu::TestLog::Message << "indices - input offset: " << indices[0] << tcu::TestLog::EndMessage;
   1354 	log << tcu::TestLog::Message << "indices - output offset: " << indices[1] << tcu::TestLog::EndMessage;
   1355 	log << tcu::TestLog::Message << "indices - additional: " << indices[2] << tcu::TestLog::EndMessage;
   1356 
   1357 	// Create descriptor data
   1358 	{
   1359 		DescriptorPoolBuilder						descriptorPoolBuilder;
   1360 		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
   1361 		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
   1362 		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
   1363 		m_descriptorPool = descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
   1364 
   1365 		DescriptorSetLayoutBuilder					setLayoutBuilder;
   1366 		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL);
   1367 		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL);
   1368 		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
   1369 		m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
   1370 
   1371 		const VkDescriptorSetAllocateInfo			descriptorSetAllocateInfo =
   1372 		{
   1373 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType	sType;
   1374 			DE_NULL,								// const void*					pNext;
   1375 			*m_descriptorPool,						// VkDescriptorPool				descriptorPool;
   1376 			1u,										// deUint32						setLayoutCount;
   1377 			&m_descriptorSetLayout.get()			// const VkDescriptorSetLayout*	pSetLayouts;
   1378 		};
   1379 
   1380 		m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
   1381 
   1382 		const VkDescriptorBufferInfo				inBufferDescriptorInfo			= makeDescriptorBufferInfo(*m_inBuffer, 0ull, m_inBufferAccess.accessRange);
   1383 		const VkDescriptorBufferInfo				outBufferDescriptorInfo			= makeDescriptorBufferInfo(*m_outBuffer, 0ull, m_outBufferAccess.accessRange);
   1384 		const VkDescriptorBufferInfo				indicesBufferDescriptorInfo		= makeDescriptorBufferInfo(*m_indicesBuffer, 0ull, 12ull);
   1385 
   1386 		DescriptorSetUpdateBuilder					setUpdateBuilder;
   1387 		setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inBufferDescriptorInfo);
   1388 		setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outBufferDescriptorInfo);
   1389 		setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &indicesBufferDescriptorInfo);
   1390 		setUpdateBuilder.update(vk, *m_device);
   1391 	}
   1392 
   1393 	// Create fence
   1394 	{
   1395 		const VkFenceCreateInfo fenceParams =
   1396 		{
   1397 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType			sType;
   1398 			DE_NULL,								// const void*				pNext;
   1399 			0u										// VkFenceCreateFlags		flags;
   1400 		};
   1401 
   1402 		m_fence = createFence(vk, *m_device, &fenceParams);
   1403 	}
   1404 
   1405 	// Get queue
   1406 	vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
   1407 
   1408 	if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
   1409 	{
   1410 		m_testEnvironment = de::MovePtr<TestEnvironment>(new ComputeEnvironment(m_context, *m_device, *m_descriptorSetLayout, *m_descriptorSet));
   1411 	}
   1412 	else
   1413 	{
   1414 		using tcu::Vec4;
   1415 
   1416 		const VkVertexInputBindingDescription		vertexInputBindingDescription =
   1417 		{
   1418 			0u,										// deUint32					binding;
   1419 			sizeof(tcu::Vec4),						// deUint32					strideInBytes;
   1420 			VK_VERTEX_INPUT_RATE_VERTEX				// VkVertexInputStepRate	inputRate;
   1421 		};
   1422 
   1423 		const VkVertexInputAttributeDescription		vertexInputAttributeDescription =
   1424 		{
   1425 			0u,										// deUint32	location;
   1426 			0u,										// deUint32	binding;
   1427 			VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
   1428 			0u										// deUint32	offset;
   1429 		};
   1430 
   1431 		AccessRangesData							vertexAccess;
   1432 		const Vec4									vertices[] =
   1433 		{
   1434 			Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
   1435 			Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
   1436 			Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
   1437 		};
   1438 		const VkDeviceSize							vertexBufferSize = static_cast<VkDeviceSize>(sizeof(vertices));
   1439 		createTestBuffer(vk, *m_device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, memAlloc, m_vertexBuffer, m_vertexBufferAlloc, vertexAccess, &populateBufferWithCopy, &vertices);
   1440 
   1441 		const GraphicsEnvironment::DrawConfig		drawWithOneVertexBuffer =
   1442 		{
   1443 			std::vector<VkBuffer>(1, *m_vertexBuffer), // std::vector<VkBuffer>	vertexBuffers;
   1444 			DE_LENGTH_OF_ARRAY(vertices),			// deUint32					vertexCount;
   1445 			1,										// deUint32					instanceCount;
   1446 			DE_NULL,								// VkBuffer					indexBuffer;
   1447 			0u,										// deUint32					indexCount;
   1448 		};
   1449 
   1450 		m_testEnvironment = de::MovePtr<TestEnvironment>(new GraphicsEnvironment(m_context,
   1451 																				 *m_device,
   1452 																				 *m_descriptorSetLayout,
   1453 																				 *m_descriptorSet,
   1454 																				 GraphicsEnvironment::VertexBindings(1, vertexInputBindingDescription),
   1455 																				 GraphicsEnvironment::VertexAttributes(1, vertexInputAttributeDescription),
   1456 																				 drawWithOneVertexBuffer));
   1457 	}
   1458 }
   1459 
   1460 // Verifies if the buffer has the value initialized by BufferAccessInstance::populateReadBuffer at a given offset.
   1461 bool AccessInstance::isExpectedValueFromInBuffer (VkDeviceSize	offsetInBytes,
   1462 												  const void*		valuePtr,
   1463 												  VkDeviceSize	valueSize)
   1464 {
   1465 	DE_ASSERT(offsetInBytes % 4 == 0);
   1466 	DE_ASSERT(offsetInBytes < m_inBufferAccess.allocSize);
   1467 
   1468 	const deUint32 valueIndex = deUint32(offsetInBytes / 4) + 2;
   1469 
   1470 	if (isUintFormat(m_bufferFormat))
   1471 	{
   1472 		return !deMemCmp(valuePtr, &valueIndex, (size_t)valueSize);
   1473 	}
   1474 	else if (isIntFormat(m_bufferFormat))
   1475 	{
   1476 		const deInt32 value = -deInt32(valueIndex);
   1477 		return !deMemCmp(valuePtr, &value, (size_t)valueSize);
   1478 	}
   1479 	else if (isFloatFormat(m_bufferFormat))
   1480 	{
   1481 		const float value = float(valueIndex);
   1482 		return !deMemCmp(valuePtr, &value, (size_t)valueSize);
   1483 	}
   1484 	else
   1485 	{
   1486 		DE_ASSERT(false);
   1487 		return false;
   1488 	}
   1489 }
   1490 
   1491 bool AccessInstance::isOutBufferValueUnchanged (VkDeviceSize offsetInBytes, VkDeviceSize valueSize)
   1492 {
   1493 	DE_ASSERT(valueSize <= 4);
   1494 	const deUint8 *const	outValuePtr		= (deUint8*)m_outBufferAlloc->getHostPtr() + offsetInBytes;
   1495 	const deUint32			defaultValue	= 0xBABABABAu;
   1496 
   1497 	return !deMemCmp(outValuePtr, &defaultValue, (size_t)valueSize);
   1498 }
   1499 
   1500 tcu::TestStatus AccessInstance::iterate (void)
   1501 {
   1502 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
   1503 	const vk::VkCommandBuffer	cmdBuffer	= m_testEnvironment->getCommandBuffer();
   1504 
   1505 	// Submit command buffer
   1506 	{
   1507 		const VkSubmitInfo	submitInfo	=
   1508 		{
   1509 			VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
   1510 			DE_NULL,						// const void*					pNext;
   1511 			0u,								// deUint32						waitSemaphoreCount;
   1512 			DE_NULL,						// const VkSemaphore*			pWaitSemaphores;
   1513 			DE_NULL,						// const VkPIpelineStageFlags*	pWaitDstStageMask;
   1514 			1u,								// deUint32						commandBufferCount;
   1515 			&cmdBuffer,						// const VkCommandBuffer*		pCommandBuffers;
   1516 			0u,								// deUint32						signalSemaphoreCount;
   1517 			DE_NULL							// const VkSemaphore*			pSignalSemaphores;
   1518 		};
   1519 
   1520 		VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
   1521 		VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
   1522 		VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
   1523 	}
   1524 
   1525 	// Prepare result buffer for read
   1526 	{
   1527 		const VkMappedMemoryRange	outBufferRange	=
   1528 		{
   1529 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//  VkStructureType	sType;
   1530 			DE_NULL,								//  const void*		pNext;
   1531 			m_outBufferAlloc->getMemory(),			//  VkDeviceMemory	mem;
   1532 			0ull,									//  VkDeviceSize	offset;
   1533 			m_outBufferAccess.allocSize,			//  VkDeviceSize	size;
   1534 		};
   1535 
   1536 		VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
   1537 	}
   1538 
   1539 	if (verifyResult())
   1540 		return tcu::TestStatus::pass("All values OK");
   1541 	else
   1542 		return tcu::TestStatus::fail("Invalid value(s) found");
   1543 }
   1544 
   1545 bool AccessInstance::verifyResult (void)
   1546 {
   1547 	std::ostringstream	logMsg;
   1548 	tcu::TestLog&		log					= m_context.getTestContext().getLog();
   1549 	const bool			isReadAccess		= (m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
   1550 	const void*			inDataPtr			= m_inBufferAlloc->getHostPtr();
   1551 	const void*			outDataPtr			= m_outBufferAlloc->getHostPtr();
   1552 	bool				allOk				= true;
   1553 	deUint32			valueNdx			= 0;
   1554 	const VkDeviceSize	maxAccessRange		= isReadAccess ? m_inBufferAccess.maxAccessRange : m_outBufferAccess.maxAccessRange;
   1555 
   1556 	for (VkDeviceSize offsetInBytes = 0; offsetInBytes < m_outBufferAccess.allocSize; offsetInBytes += 4)
   1557 	{
   1558 		const deUint8*		outValuePtr		= static_cast<const deUint8*>(outDataPtr) + offsetInBytes;
   1559 		const size_t		outValueSize	= static_cast<size_t>(deMinu64(4, (m_outBufferAccess.allocSize - offsetInBytes)));
   1560 
   1561 		if (offsetInBytes >= RobustAccessWithPointersTest::s_numberOfBytesAccessed)
   1562 		{
   1563 			// The shader will only write 16 values into the result buffer. The rest of the values
   1564 			// should remain unchanged or may be modified if we are writing out of bounds.
   1565 			if (!isOutBufferValueUnchanged(offsetInBytes, outValueSize)
   1566 				&& (isReadAccess || !isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, outValuePtr, 4)))
   1567 			{
   1568 				logMsg << "\nValue " << valueNdx++ << " has been modified with an unknown value: " << *(static_cast<const deUint32*>(static_cast<const void*>(outValuePtr)));
   1569 				allOk = false;
   1570 			}
   1571 		}
   1572 		else
   1573 		{
   1574 			const deInt32	distanceToOutOfBounds	= static_cast<deInt32>(maxAccessRange) - static_cast<deInt32>(offsetInBytes);
   1575 			bool			isOutOfBoundsAccess		= false;
   1576 
   1577 			logMsg << "\n" << valueNdx++ << ": ";
   1578 
   1579 			logValue(logMsg, outValuePtr, m_bufferFormat, outValueSize);
   1580 
   1581 			if (m_accessOutOfBackingMemory)
   1582 				isOutOfBoundsAccess = true;
   1583 
   1584 			// Check if the shader operation accessed an operand located less than 16 bytes away
   1585 			// from the out of bounds address.
   1586 			if (!isOutOfBoundsAccess && distanceToOutOfBounds < 16)
   1587 			{
   1588 				deUint32 operandSize = 0;
   1589 
   1590 				switch (m_shaderType)
   1591 				{
   1592 					case SHADER_TYPE_SCALAR_COPY:
   1593 						operandSize		= 4; // Size of scalar
   1594 						break;
   1595 
   1596 					case SHADER_TYPE_VECTOR_COPY:
   1597 						operandSize		= 4 * 4; // Size of vec4
   1598 						break;
   1599 
   1600 					case SHADER_TYPE_MATRIX_COPY:
   1601 						operandSize		= 4 * 16; // Size of mat4
   1602 						break;
   1603 
   1604 					default:
   1605 						DE_ASSERT(false);
   1606 				}
   1607 
   1608 				isOutOfBoundsAccess = (((offsetInBytes / operandSize) + 1) * operandSize > maxAccessRange);
   1609 			}
   1610 
   1611 			if (isOutOfBoundsAccess)
   1612 			{
   1613 				logMsg << " (out of bounds " << (isReadAccess ? "read": "write") << ")";
   1614 
   1615 				const bool	isValuePartiallyOutOfBounds = ((distanceToOutOfBounds > 0) && ((deUint32)distanceToOutOfBounds < 4));
   1616 				bool		isValidValue				= false;
   1617 
   1618 				if (isValuePartiallyOutOfBounds && !m_accessOutOfBackingMemory)
   1619 				{
   1620 					// The value is partially out of bounds
   1621 
   1622 					bool	isOutOfBoundsPartOk  = true;
   1623 					bool	isWithinBoundsPartOk = true;
   1624 
   1625 					if (isReadAccess)
   1626 					{
   1627 						isWithinBoundsPartOk	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, outValuePtr, distanceToOutOfBounds);
   1628 						isOutOfBoundsPartOk		= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, (deUint8*)outValuePtr + distanceToOutOfBounds , outValueSize - distanceToOutOfBounds);
   1629 					}
   1630 					else
   1631 					{
   1632 						isWithinBoundsPartOk	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, outValuePtr, distanceToOutOfBounds)
   1633 												  || isOutBufferValueUnchanged(offsetInBytes, distanceToOutOfBounds);
   1634 
   1635 						isOutOfBoundsPartOk		= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, (deUint8*)outValuePtr + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds)
   1636 												  || isOutBufferValueUnchanged(offsetInBytes + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds);
   1637 					}
   1638 
   1639 					logMsg << ", first " << distanceToOutOfBounds << " byte(s) " << (isWithinBoundsPartOk ? "OK": "wrong");
   1640 					logMsg << ", last " << outValueSize - distanceToOutOfBounds << " byte(s) " << (isOutOfBoundsPartOk ? "OK": "wrong");
   1641 
   1642 					isValidValue	= isWithinBoundsPartOk && isOutOfBoundsPartOk;
   1643 				}
   1644 				else
   1645 				{
   1646 					if (isReadAccess)
   1647 					{
   1648 						isValidValue	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, outValuePtr, outValueSize);
   1649 					}
   1650 					else
   1651 					{
   1652 						isValidValue	= isOutBufferValueUnchanged(offsetInBytes, outValueSize);
   1653 
   1654 						if (!isValidValue)
   1655 						{
   1656 							// Out of bounds writes may modify values withing the memory ranges bound to the buffer
   1657 							isValidValue	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.allocSize, outValuePtr, outValueSize);
   1658 
   1659 							if (isValidValue)
   1660 								logMsg << ", OK, written within the memory range bound to the buffer";
   1661 						}
   1662 					}
   1663 				}
   1664 
   1665 				if (!isValidValue)
   1666 				{
   1667 					// Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
   1668 					// or the maximum representable positive integer value (if the format is integer-based).
   1669 
   1670 					const bool	canMatchVec4Pattern	= (isReadAccess
   1671 													&& !isValuePartiallyOutOfBounds
   1672 													&& (m_shaderType == SHADER_TYPE_VECTOR_COPY)
   1673 													&& (offsetInBytes / 4 + 1) % 4 == 0);
   1674 					bool		matchesVec4Pattern	= false;
   1675 
   1676 					if (canMatchVec4Pattern)
   1677 					{
   1678 						matchesVec4Pattern	= verifyOutOfBoundsVec4(static_cast<const deUint32*>(static_cast<const void*>(outValuePtr)) - 3, m_bufferFormat);
   1679 					}
   1680 
   1681 					if (!canMatchVec4Pattern || !matchesVec4Pattern)
   1682 					{
   1683 						logMsg << ". Failed: ";
   1684 
   1685 						if (isReadAccess)
   1686 						{
   1687 							logMsg << "expected value within the buffer range or 0";
   1688 
   1689 							if (canMatchVec4Pattern)
   1690 								logMsg << ", or the [0, 0, 0, x] pattern";
   1691 						}
   1692 						else
   1693 						{
   1694 							logMsg << "written out of the range";
   1695 						}
   1696 
   1697 						allOk = false;
   1698 					}
   1699 				}
   1700 			}
   1701 			else // We are within bounds
   1702 			{
   1703 				if (isReadAccess)
   1704 				{
   1705 					if (!isExpectedValueFromInBuffer(offsetInBytes, outValuePtr, 4))
   1706 					{
   1707 						logMsg << ", Failed: unexpected value";
   1708 						allOk = false;
   1709 					}
   1710 				}
   1711 				else
   1712 				{
   1713 					// Out of bounds writes may change values within the bounds.
   1714 					if (!isValueWithinBufferOrZero(inDataPtr, m_inBufferAccess.accessRange, outValuePtr, 4))
   1715 					{
   1716 						logMsg << ", Failed: unexpected value";
   1717 						allOk = false;
   1718 					}
   1719 				}
   1720 			}
   1721 		}
   1722 	}
   1723 
   1724 	log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
   1725 
   1726 	return allOk;
   1727 }
   1728 
   1729 // BufferReadInstance
   1730 
   1731 ReadInstance::ReadInstance (Context&				context,
   1732 							Move<VkDevice>			device,
   1733 							ShaderType				shaderType,
   1734 							VkShaderStageFlags		shaderStage,
   1735 							VkFormat				bufferFormat,
   1736 							//bool					readFromStorage,
   1737 							VkDeviceSize			inBufferAccessRange,
   1738 							bool					accessOutOfBackingMemory)
   1739 
   1740 	: AccessInstance	(context, device, shaderType, shaderStage, bufferFormat,
   1741 						 BUFFER_ACCESS_TYPE_READ_FROM_STORAGE,
   1742 						 inBufferAccessRange, RobustAccessWithPointersTest::s_numberOfBytesAccessed,
   1743 						 accessOutOfBackingMemory)
   1744 {
   1745 }
   1746 
   1747 // BufferWriteInstance
   1748 
   1749 WriteInstance::WriteInstance (Context&				context,
   1750 							  Move<VkDevice>		device,
   1751 							  ShaderType			shaderType,
   1752 							  VkShaderStageFlags	shaderStage,
   1753 							  VkFormat				bufferFormat,
   1754 							  VkDeviceSize			writeBufferAccessRange,
   1755 							  bool					accessOutOfBackingMemory)
   1756 
   1757 	: AccessInstance	(context, device, shaderType, shaderStage, bufferFormat,
   1758 						 BUFFER_ACCESS_TYPE_WRITE_TO_STORAGE,
   1759 						 RobustAccessWithPointersTest::s_numberOfBytesAccessed, writeBufferAccessRange,
   1760 						 accessOutOfBackingMemory)
   1761 {
   1762 }
   1763 
   1764 } // unnamed namespace
   1765 
   1766 tcu::TestCaseGroup* createBufferAccessWithVariablePointersTests(tcu::TestContext& testCtx)
   1767 {
   1768 	// Lets make group for the tests
   1769 	de::MovePtr<tcu::TestCaseGroup> bufferAccessWithVariablePointersTests	(new tcu::TestCaseGroup(testCtx, "through_pointers", ""));
   1770 
   1771 	// Lets add subgroups to better organise tests
   1772 	de::MovePtr<tcu::TestCaseGroup> computeWithVariablePointersTests		(new tcu::TestCaseGroup(testCtx, "compute", ""));
   1773 	de::MovePtr<tcu::TestCaseGroup> computeReads							(new tcu::TestCaseGroup(testCtx, "reads", ""));
   1774 	de::MovePtr<tcu::TestCaseGroup> computeWrites							(new tcu::TestCaseGroup(testCtx, "writes", ""));
   1775 
   1776 	de::MovePtr<tcu::TestCaseGroup> graphicsWithVariablePointersTests		(new tcu::TestCaseGroup(testCtx, "graphics", ""));
   1777 	de::MovePtr<tcu::TestCaseGroup> graphicsReads							(new tcu::TestCaseGroup(testCtx, "reads", ""));
   1778 	de::MovePtr<tcu::TestCaseGroup> graphicsReadsVertex						(new tcu::TestCaseGroup(testCtx, "vertex", ""));
   1779 	de::MovePtr<tcu::TestCaseGroup> graphicsReadsFragment					(new tcu::TestCaseGroup(testCtx, "fragment", ""));
   1780 	de::MovePtr<tcu::TestCaseGroup> graphicsWrites							(new tcu::TestCaseGroup(testCtx, "writes", ""));
   1781 	de::MovePtr<tcu::TestCaseGroup> graphicsWritesVertex					(new tcu::TestCaseGroup(testCtx, "vertex", ""));
   1782 	de::MovePtr<tcu::TestCaseGroup> graphicsWritesFragment					(new tcu::TestCaseGroup(testCtx, "fragment", ""));
   1783 
   1784 	// A struct for describing formats
   1785 	struct Formats
   1786 	{
   1787 		const VkFormat		value;
   1788 		const char * const	name;
   1789 	};
   1790 
   1791 	const Formats			bufferFormats[]			=
   1792 	{
   1793 		{ VK_FORMAT_R32_SINT,		"s32" },
   1794 		{ VK_FORMAT_R32_UINT,		"u32" },
   1795 		{ VK_FORMAT_R32_SFLOAT,		"f32" }
   1796 	};
   1797 	const deUint8			bufferFormatsCount		= static_cast<deUint8>(DE_LENGTH_OF_ARRAY(bufferFormats));
   1798 
   1799 	// Amounts of data to copy
   1800 	const VkDeviceSize		rangeSizes[]			=
   1801 	{
   1802 		1ull, 3ull, 4ull, 16ull, 32ull
   1803 	};
   1804 	const deUint8			rangeSizesCount			= static_cast<deUint8>(DE_LENGTH_OF_ARRAY(rangeSizes));
   1805 
   1806 	// gather above data into one array
   1807 	const struct ShaderTypes
   1808 	{
   1809 		const ShaderType			value;
   1810 		const char * const			name;
   1811 		const Formats* const		formats;
   1812 		const deUint8				formatsCount;
   1813 		const VkDeviceSize* const	sizes;
   1814 		const deUint8				sizesCount;
   1815 	}						types[]					=
   1816 	{
   1817 		{ SHADER_TYPE_VECTOR_COPY,	"vec4",		bufferFormats,			bufferFormatsCount,			rangeSizes,			rangeSizesCount },
   1818 		{ SHADER_TYPE_SCALAR_COPY,	"scalar",	bufferFormats,			bufferFormatsCount,			rangeSizes,			rangeSizesCount }
   1819 	};
   1820 
   1821 	// Specify to which subgroups put various tests
   1822 	const struct ShaderStages
   1823 	{
   1824 		VkShaderStageFlags					stage;
   1825 		de::MovePtr<tcu::TestCaseGroup>&	reads;
   1826 		de::MovePtr<tcu::TestCaseGroup>&	writes;
   1827 	}						stages[]				=
   1828 	{
   1829 		{ VK_SHADER_STAGE_VERTEX_BIT,		graphicsReadsVertex,	graphicsWritesVertex },
   1830 		{ VK_SHADER_STAGE_FRAGMENT_BIT,		graphicsReadsFragment,	graphicsWritesFragment },
   1831 		{ VK_SHADER_STAGE_COMPUTE_BIT,		computeReads,			computeWrites }
   1832 	};
   1833 
   1834 	// Eventually specify if memory used should be in the "inaccesible" portion of buffer or entirely outside of buffer
   1835 	const char* const		backingMemory[]			= { "in_memory", "out_of_memory" };
   1836 
   1837 	for (deInt32 stageId = 0; stageId < DE_LENGTH_OF_ARRAY(stages); ++stageId)
   1838 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); ++i)
   1839 			for (int j = 0; j < types[i].formatsCount; ++j)
   1840 				for (int k = 0; k < types[i].sizesCount; ++k)
   1841 					for (int s = 0; s < DE_LENGTH_OF_ARRAY(backingMemory); ++s)
   1842 					{
   1843 						std::ostringstream	name;
   1844 						name << types[i].sizes[k] << "B_" << backingMemory[s] << "_with_" << types[i].name << '_' << types[i].formats[j].name;
   1845 						stages[stageId].reads->addChild(new RobustReadTest(testCtx, name.str().c_str(), "", stages[stageId].stage, types[i].value, types[i].formats[j].value, types[i].sizes[k], s != 0));
   1846 					}
   1847 
   1848 	for (deInt32 stageId = 0; stageId < DE_LENGTH_OF_ARRAY(stages); ++stageId)
   1849 		for (int i=0; i<DE_LENGTH_OF_ARRAY(types); ++i)
   1850 			for (int j=0; j<types[i].formatsCount; ++j)
   1851 				for (int k = 0; k<types[i].sizesCount; ++k)
   1852 					for (int s = 0; s < DE_LENGTH_OF_ARRAY(backingMemory); ++s)
   1853 					{
   1854 						std::ostringstream	name;
   1855 						name << types[i].sizes[k] << "B_" << backingMemory[s] << "_with_" << types[i].name << '_' << types[i].formats[j].name;
   1856 						stages[stageId].writes->addChild(new RobustWriteTest(testCtx, name.str().c_str(), "", stages[stageId].stage, types[i].value, types[i].formats[j].value, types[i].sizes[k], s != 0));
   1857 					}
   1858 
   1859 	graphicsReads->addChild(graphicsReadsVertex.release());
   1860 	graphicsReads->addChild(graphicsReadsFragment.release());
   1861 
   1862 	graphicsWrites->addChild(graphicsWritesVertex.release());
   1863 	graphicsWrites->addChild(graphicsWritesFragment.release());
   1864 
   1865 	graphicsWithVariablePointersTests->addChild(graphicsReads.release());
   1866 	graphicsWithVariablePointersTests->addChild(graphicsWrites.release());
   1867 
   1868 	computeWithVariablePointersTests->addChild(computeReads.release());
   1869 	computeWithVariablePointersTests->addChild(computeWrites.release());
   1870 
   1871 	bufferAccessWithVariablePointersTests->addChild(graphicsWithVariablePointersTests.release());
   1872 	bufferAccessWithVariablePointersTests->addChild(computeWithVariablePointersTests.release());
   1873 
   1874 	return bufferAccessWithVariablePointersTests.release();
   1875 }
   1876 
   1877 } // robustness
   1878 } // vkt
   1879