Home | History | Annotate | Download | only in protected_memory
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2017 The Khronos Group Inc.
      6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  *//*!
     21  * \file
     22  * \brief Protected memory storage buffer tests
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktProtectedMemStorageBufferTests.hpp"
     26 
     27 #include "deRandom.hpp"
     28 #include "deStringUtil.hpp"
     29 #include "tcuTestLog.hpp"
     30 #include "tcuVector.hpp"
     31 #include "tcuStringTemplate.hpp"
     32 
     33 #include "vkPrograms.hpp"
     34 #include "vktTestCase.hpp"
     35 #include "vktTestGroupUtil.hpp"
     36 #include "vkTypeUtil.hpp"
     37 #include "vkBuilderUtil.hpp"
     38 #include "vkCmdUtil.hpp"
     39 
     40 #include "vktProtectedMemBufferValidator.hpp"
     41 #include "vktProtectedMemUtils.hpp"
     42 #include "vktProtectedMemContext.hpp"
     43 
     44 namespace vkt
     45 {
     46 namespace ProtectedMem
     47 {
     48 
     49 namespace
     50 {
     51 
     52 enum {
     53 	RENDER_HEIGHT	= 128,
     54 	RENDER_WIDTH	= 128,
     55 };
     56 
     57 enum {
     58 	RANDOM_TEST_COUNT	= 10,
     59 };
     60 
     61 enum SSBOTestType {
     62 	SSBO_READ,
     63 	SSBO_WRITE,
     64 	SSBO_ATOMIC
     65 };
     66 
     67 enum SSBOAtomicType {
     68 	ATOMIC_ADD,
     69 	ATOMIC_MIN,
     70 	ATOMIC_MAX,
     71 	ATOMIC_AND,
     72 	ATOMIC_OR,
     73 	ATOMIC_XOR,
     74 	ATOMIC_EXCHANGE,
     75 	ATOMIC_COMPSWAP
     76 };
     77 
     78 
     79 const char* getSSBOTestDescription (SSBOTestType type)
     80 {
     81 	switch (type) {
     82 		case SSBO_READ:		return "Test for read storage buffer on protected memory.";
     83 		case SSBO_WRITE:	return "Test for write storage buffer on protected memory.";
     84 		case SSBO_ATOMIC:	return "Test for atomic storage buffer on protected memory.";
     85 		default: DE_FATAL("Invalid SSBO test type"); return "";
     86 	}
     87 }
     88 
     89 const char* getSSBOTypeString (SSBOTestType type)
     90 {
     91 	switch (type) {
     92 		case SSBO_READ:		return "read";
     93 		case SSBO_WRITE:	return "write";
     94 		case SSBO_ATOMIC:	return "atomic";
     95 		default: DE_FATAL("Invalid SSBO test type"); return "";
     96 	}
     97 }
     98 
     99 const char* getShaderTypeString (const glu::ShaderType shaderType)
    100 {
    101 	switch (shaderType) {
    102 		case glu::SHADERTYPE_FRAGMENT:	return "fragment";
    103 		case glu::SHADERTYPE_COMPUTE:	return "compute";
    104 		default: DE_FATAL("Invalid shader type"); return "";
    105 	}
    106 }
    107 
    108 const char* getSSBOAtomicTypeString (SSBOAtomicType type)
    109 {
    110 	switch (type)
    111 	{
    112 		case ATOMIC_ADD:		return "add";
    113 		case ATOMIC_MIN:		return "min";
    114 		case ATOMIC_MAX:		return "max";
    115 		case ATOMIC_AND:		return "and";
    116 		case ATOMIC_OR:			return "or";
    117 		case ATOMIC_XOR:		return "xor";
    118 		case ATOMIC_EXCHANGE:	return "exchange";
    119 		case ATOMIC_COMPSWAP:	return "compswap";
    120 		default: DE_FATAL("Invalid SSBO atomic operation type"); return "";
    121 	}
    122 }
    123 
    124 void static addBufferCopyCmd (const vk::DeviceInterface&	vk,
    125 							  vk::VkCommandBuffer			cmdBuffer,
    126 							  deUint32						queueFamilyIndex,
    127 							  vk::VkBuffer					srcBuffer,
    128 							  vk::VkBuffer					dstBuffer,
    129 							  deUint32						copySize)
    130 {
    131 	const vk::VkBufferMemoryBarrier		dstWriteStartBarrier	=
    132 	{
    133 		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType		sType
    134 		DE_NULL,											// const void*			pNext
    135 		0,													// VkAccessFlags		srcAccessMask
    136 		vk::VK_ACCESS_SHADER_WRITE_BIT,						// VkAccessFlags		dstAccessMask
    137 		queueFamilyIndex,									// uint32_t				srcQueueFamilyIndex
    138 		queueFamilyIndex,									// uint32_t				dstQueueFamilyIndex
    139 		dstBuffer,											// VkBuffer				buffer
    140 		0u,													// VkDeviceSize			offset
    141 		VK_WHOLE_SIZE,										// VkDeviceSize			size
    142 	};
    143 
    144 	vk.cmdPipelineBarrier(cmdBuffer,
    145 						  vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,	// srcStageMask
    146 						  vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,	// dstStageMask
    147 						  (vk::VkDependencyFlags)0,
    148 						  0, (const vk::VkMemoryBarrier*)DE_NULL,
    149 						  1, &dstWriteStartBarrier,
    150 						  0, (const vk::VkImageMemoryBarrier*)DE_NULL);
    151 
    152 	const vk::VkBufferCopy				copyRegion				=
    153 	{
    154 		0,					// VkDeviceSize	srcOffset
    155 		0,					// VkDeviceSize	dstOffset
    156 		copySize			// VkDeviceSize	size
    157 	};
    158 	vk.cmdCopyBuffer(cmdBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
    159 
    160 	const vk::VkBufferMemoryBarrier		dstWriteEndBarrier		=
    161 	{
    162 		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType		sType
    163 		DE_NULL,											// const void*			pNext
    164 		vk::VK_ACCESS_SHADER_WRITE_BIT,						// VkAccessFlags		srcAccessMask
    165 		vk::VK_ACCESS_SHADER_READ_BIT,						// VkAccessFlags		dstAccessMask
    166 		queueFamilyIndex,									// uint32_t				srcQueueFamilyIndex
    167 		queueFamilyIndex,									// uint32_t				dstQueueFamilyIndex
    168 		dstBuffer,											// VkBuffer				buffer
    169 		0u,													// VkDeviceSize			offset
    170 		VK_WHOLE_SIZE,										// VkDeviceSize			size
    171 	};
    172 	vk.cmdPipelineBarrier(cmdBuffer,
    173 						  vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,		// srcStageMask
    174 						  vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,	// dstStageMask
    175 						  (vk::VkDependencyFlags)0,
    176 						  0, (const vk::VkMemoryBarrier*)DE_NULL,
    177 						  1, &dstWriteEndBarrier,
    178 						  0, (const vk::VkImageMemoryBarrier*)DE_NULL);
    179 
    180 }
    181 
    182 template<typename T>
    183 class StorageBufferTestInstance : public ProtectedTestInstance
    184 {
    185 public:
    186 								StorageBufferTestInstance	(Context&					ctx,
    187 															 const SSBOTestType			testType,
    188 															 const glu::ShaderType		shaderType,
    189 															 const tcu::UVec4			testInput,
    190 															 const BufferValidator<T>&	validator);
    191 	virtual tcu::TestStatus		iterate						(void);
    192 
    193 private:
    194 	tcu::TestStatus				executeFragmentTest			(void);
    195 	tcu::TestStatus				executeComputeTest			(void);
    196 
    197 	const SSBOTestType			m_testType;
    198 	const glu::ShaderType		m_shaderType;
    199 	const tcu::UVec4			m_testInput;
    200 	const BufferValidator<T>&	m_validator;
    201 	const vk::VkFormat			m_imageFormat;
    202 };
    203 
    204 template<typename T>
    205 class StorageBufferTestCase : public TestCase
    206 {
    207 public:
    208 								StorageBufferTestCase	(tcu::TestContext&			testctx,
    209 														 const SSBOTestType			testType,
    210 														 const glu::ShaderType		shaderType,
    211 														 const char*				name,
    212 														 const tcu::UVec4			testInput,
    213 														 ValidationDataStorage<T>	validationData,
    214 														 const std::string&			extraShader = "")
    215 									: TestCase		(testctx, name, getSSBOTestDescription(testType))
    216 									, m_testType	(testType)
    217 									, m_shaderType	(shaderType)
    218 									, m_testInput	(testInput)
    219 									, m_validator	(validationData)
    220 									, m_extraShader	(extraShader)
    221 								{
    222 								}
    223 	virtual TestInstance*		createInstance			(Context& ctx) const
    224 								{
    225 									return new StorageBufferTestInstance<T>(ctx, m_testType, m_shaderType, m_testInput, m_validator);
    226 								}
    227 	virtual void				initPrograms			(vk::SourceCollections& programCollection) const;
    228 
    229 	virtual						~StorageBufferTestCase	(void) {}
    230 
    231 private:
    232 	const SSBOTestType			m_testType;
    233 	const glu::ShaderType		m_shaderType;
    234 	const tcu::UVec4			m_testInput;
    235 	const BufferValidator<T>	m_validator;
    236 	const std::string			m_extraShader;
    237 };
    238 
    239 template<typename T>
    240 StorageBufferTestInstance<T>::StorageBufferTestInstance	 (Context&					ctx,
    241 														  const SSBOTestType		testType,
    242 														  const glu::ShaderType		shaderType,
    243 														  const tcu::UVec4			testInput,
    244 														  const BufferValidator<T>&	validator)
    245 	: ProtectedTestInstance	(ctx)
    246 	, m_testType			(testType)
    247 	, m_shaderType			(shaderType)
    248 	, m_testInput			(testInput)
    249 	, m_validator			(validator)
    250 	, m_imageFormat			(vk::VK_FORMAT_R8G8B8A8_UNORM)
    251 {
    252 }
    253 
    254 template<typename T>
    255 void StorageBufferTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
    256 {
    257 	const char* vertexShader =
    258 		"#version 450\n"
    259 		"layout(location=0) out vec4 vIndex;\n"
    260 		"void main() {\n"
    261 		"    vec2 pos[4] = vec2[4]( vec2(-0.7, 0.7), vec2(0.7, 0.7), vec2(0.0, -0.7), vec2(-0.7, -0.7) );\n"
    262 		"    vIndex = vec4(gl_VertexIndex);\n"
    263 		"    gl_PointSize = 1.0;\n"
    264 		"    gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);\n"
    265 		"}";
    266 
    267 	//  set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4)
    268 	//  set = 0, location = 2 -> buffer ProtectedTestBufferSource (uvec4)
    269 	const char* readShaderTemplateStr =
    270 		"#version 450\n"
    271 		"${INPUT_DECLARATION}\n"
    272 		"\n"
    273 		"layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n"
    274 		"{\n"
    275 		"    highp uvec4 protectedTestResultBuffer;\n"
    276 		"};\n"
    277 		"\n"
    278 		"layout(set=0, binding=2, std140) buffer ProtectedTestBufferSource\n"
    279 		"{\n"
    280 		"    highp uvec4 protectedTestBufferSource;\n"
    281 		"};\n"
    282 		"\n"
    283 		"void main (void)\n"
    284 		"{\n"
    285 		"    protectedTestResultBuffer = protectedTestBufferSource;\n"
    286 		"    ${FRAGMENT_OUTPUT}\n"
    287 		"}\n";
    288 
    289 	//  set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4)
    290 	//  set = 0, location = 1 -> uniform Data (uvec4)
    291 	const char* writeShaderTemplateStr =
    292 		"#version 450\n"
    293 		"${INPUT_DECLARATION}\n"
    294 		"\n"
    295 		"layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n"
    296 		"{\n"
    297 		"    highp uvec4 protectedTestResultBuffer;\n"
    298 		"};\n"
    299 		"\n"
    300 		"layout(set=0, binding=1, std140) uniform Data\n"
    301 		"{\n"
    302 		"    highp uvec4 testInput;\n"
    303 		"};\n"
    304 		"\n"
    305 		"void main (void)\n"
    306 		"{\n"
    307 		"    protectedTestResultBuffer = testInput;\n"
    308 		"    ${FRAGMENT_OUTPUT}\n"
    309 		"}\n";
    310 
    311 	//  set = 0, location = 0 -> buffer ProtectedTestBuffer (uint [4])
    312 	const char* atomicTestShaderTemplateStr =
    313 		"#version 450\n"
    314 		"${INPUT_DECLARATION}\n"
    315 		"\n"
    316 		"layout(set=0, binding=0, std430) buffer ProtectedTestBuffer\n"
    317 		"{\n"
    318 		"    highp uint protectedTestResultBuffer[4];\n"
    319 		"};\n"
    320 		"\n"
    321 		"void main (void)\n"
    322 		"{\n"
    323 		"    uint i = uint(${INVOCATION_ID});\n"
    324 		"    ${ATOMIC_FUNCTION_CALL}\n"
    325 		"    ${FRAGMENT_OUTPUT}\n"
    326 		"}\n";
    327 
    328 	const char*							shaderTemplateStr;
    329 	std::map<std::string, std::string>	shaderParam;
    330 	switch (m_testType) {
    331 		case SSBO_READ:		shaderTemplateStr = readShaderTemplateStr; break;
    332 		case SSBO_WRITE:	shaderTemplateStr = writeShaderTemplateStr; break;
    333 		case SSBO_ATOMIC:	{
    334 			shaderTemplateStr = atomicTestShaderTemplateStr;
    335 			shaderParam["ATOMIC_FUNCTION_CALL"] = m_extraShader;
    336 			break;
    337 		}
    338 		default: DE_FATAL("Incorrect SSBO test type"); return;
    339 	}
    340 
    341 	if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
    342 	{
    343 		shaderParam["INPUT_DECLARATION"]		= "layout(location=0) out mediump vec4 o_color;\n"
    344 												  "layout(location=0) in vec4 vIndex;\n";
    345 		shaderParam["FRAGMENT_OUTPUT"]			= "o_color = vec4( 0.0, 0.4, 1.0, 1.0 );\n";
    346 		shaderParam["INVOCATION_ID"]			= "vIndex.x";
    347 
    348 		programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader);
    349 		programCollection.glslSources.add("TestShader") << glu::FragmentSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam));
    350 	}
    351 	else if (m_shaderType == glu::SHADERTYPE_COMPUTE)
    352 	{
    353 		shaderParam["INPUT_DECLARATION"]		= "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
    354 		shaderParam["FRAGMENT_OUTPUT"]			= "";
    355 		shaderParam["INVOCATION_ID"]			= "gl_GlobalInvocationID.x";
    356 		programCollection.glslSources.add("TestShader") << glu::ComputeSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam));
    357 	}
    358 	else
    359 		DE_FATAL("Incorrect shader type");
    360 
    361 	m_validator.initPrograms(programCollection);
    362 }
    363 
    364 template<typename T>
    365 tcu::TestStatus StorageBufferTestInstance<T>::executeFragmentTest(void)
    366 {
    367 	ProtectedContext&						ctx					(m_protectedContext);
    368 	const vk::DeviceInterface&				vk					= ctx.getDeviceInterface();
    369 	const vk::VkDevice						device				= ctx.getDevice();
    370 	const vk::VkQueue						queue				= ctx.getQueue();
    371 	const deUint32							queueFamilyIndex	= ctx.getQueueFamilyIndex();
    372 
    373 	const deUint32							testUniformSize		= sizeof(m_testInput);
    374 	de::UniquePtr<vk::BufferWithMemory>		testUniform			(makeBuffer(ctx,
    375 																		PROTECTION_DISABLED,
    376 																		queueFamilyIndex,
    377 																		testUniformSize,
    378 																		vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
    379 																		 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    380 																		vk::MemoryRequirement::HostVisible));
    381 
    382 	// Set the test input uniform data
    383 	{
    384 		deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize);
    385 		vk::flushMappedMemoryRange(vk, device, testUniform->getAllocation().getMemory(), testUniform->getAllocation().getOffset(), testUniformSize);
    386 	}
    387 	const deUint32							testBufferSize		= sizeof(ValidationDataStorage<T>);
    388 	de::MovePtr<vk::BufferWithMemory>		testBuffer			(makeBuffer(ctx,
    389 																			PROTECTION_ENABLED,
    390 																			queueFamilyIndex,
    391 																			testBufferSize,
    392 																			vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
    393 																			 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    394 																			vk::MemoryRequirement::Protected));
    395     de::MovePtr<vk::BufferWithMemory>		testBufferSource			(makeBuffer(ctx,
    396 																			PROTECTION_ENABLED,
    397 																			queueFamilyIndex,
    398 																			testBufferSize,
    399 																			vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
    400 																			 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    401 																			vk::MemoryRequirement::Protected));
    402 
    403 	vk::Move<vk::VkShaderModule>			vertexShader		(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0));
    404 	vk::Unique<vk::VkShaderModule>			testShader			(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0));
    405 
    406 	// Create descriptors
    407 	vk::Unique<vk::VkDescriptorSetLayout>	descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
    408 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL)
    409 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL)
    410 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL)
    411 		.build(vk, device));
    412 	vk::Unique<vk::VkDescriptorPool>		descriptorPool(vk::DescriptorPoolBuilder()
    413 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
    414 		.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
    415 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
    416 		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
    417 	vk::Unique<vk::VkDescriptorSet>			descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
    418 
    419 	// Update descriptor set information
    420 	{
    421 		vk::VkDescriptorBufferInfo	descTestBuffer			= makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize);
    422 		vk::VkDescriptorBufferInfo	descTestUniform			= makeDescriptorBufferInfo(**testUniform, 0, testUniformSize);
    423 		vk::VkDescriptorBufferInfo	descTestBufferSource	= makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize);
    424 
    425 		vk::DescriptorSetUpdateBuilder()
    426 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer)
    427 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform)
    428 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource)
    429 			.update(vk, device);
    430 	}
    431 
    432 	// Create output image
    433 	de::MovePtr<vk::ImageWithMemory>		colorImage			(createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
    434 																			   RENDER_WIDTH, RENDER_HEIGHT,
    435 																			   m_imageFormat,
    436 																			   vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_SAMPLED_BIT));
    437 	vk::Unique<vk::VkImageView>				colorImageView		(createImageView(ctx, **colorImage, m_imageFormat));
    438 	vk::Unique<vk::VkRenderPass>			renderPass			(createRenderPass(ctx, m_imageFormat));
    439 	vk::Unique<vk::VkFramebuffer>			framebuffer			(createFramebuffer(ctx, RENDER_WIDTH, RENDER_HEIGHT, *renderPass, *colorImageView));
    440 
    441 	// Build pipeline
    442 	vk::Unique<vk::VkPipelineLayout>		pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
    443 	vk::Unique<vk::VkCommandPool>			cmdPool				(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
    444 	vk::Unique<vk::VkCommandBuffer>			cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
    445 
    446 	// Create pipeline
    447 	vk::Unique<vk::VkPipeline>				graphicsPipeline	(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass,
    448 																					  *vertexShader, *testShader,
    449 																					  std::vector<vk::VkVertexInputBindingDescription>(),
    450 																					  std::vector<vk::VkVertexInputAttributeDescription>(),
    451 																					  tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT),
    452 																					  vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST));
    453 
    454 	beginCommandBuffer(vk, *cmdBuffer);
    455 
    456 	if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC)
    457 	{
    458 		vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource;
    459 		addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize);
    460 	}
    461 
    462 	// Start image barrier
    463 	{
    464 		const vk::VkImageMemoryBarrier	startImgBarrier		=
    465 		{
    466 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// sType
    467 			DE_NULL,											// pNext
    468 			0,													// srcAccessMask
    469 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// dstAccessMask
    470 			vk::VK_IMAGE_LAYOUT_UNDEFINED,						// oldLayout
    471 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// newLayout
    472 			queueFamilyIndex,									// srcQueueFamilyIndex
    473 			queueFamilyIndex,									// dstQueueFamilyIndex
    474 			**colorImage,										// image
    475 			{
    476 				vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
    477 				0u,												// baseMipLevel
    478 				1u,												// mipLevels
    479 				0u,												// baseArraySlice
    480 				1u,												// subresourceRange
    481 			}
    482 		};
    483 
    484 		vk.cmdPipelineBarrier(*cmdBuffer,
    485 							  vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,				// srcStageMask
    486 							  vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// dstStageMask
    487 							  (vk::VkDependencyFlags)0,
    488 							  0, (const vk::VkMemoryBarrier*)DE_NULL,
    489 							  0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
    490 							  1, &startImgBarrier);
    491 	}
    492 
    493 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f));
    494 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
    495 	vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
    496 
    497 	vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u);
    498 	endRenderPass(vk, *cmdBuffer);
    499 
    500 	{
    501 		const vk::VkImageMemoryBarrier	endImgBarrier		=
    502 		{
    503 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// sType
    504 			DE_NULL,											// pNext
    505 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// srcAccessMask
    506 			vk::VK_ACCESS_SHADER_READ_BIT,						// dstAccessMask
    507 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// oldLayout
    508 			vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,		// newLayout
    509 			queueFamilyIndex,									// srcQueueFamilyIndex
    510 			queueFamilyIndex,									// dstQueueFamilyIndex
    511 			**colorImage,										// image
    512 			{
    513 				vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
    514 				0u,												// baseMipLevel
    515 				1u,												// mipLevels
    516 				0u,												// baseArraySlice
    517 				1u,												// subresourceRange
    518 			}
    519 		};
    520 		vk.cmdPipelineBarrier(*cmdBuffer,
    521 							  vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// srcStageMask
    522 							  vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,				// dstStageMask
    523 							  (vk::VkDependencyFlags)0,
    524 							  0, (const vk::VkMemoryBarrier*)DE_NULL,
    525 							  0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
    526 							  1, &endImgBarrier);
    527 	}
    528 
    529 	endCommandBuffer(vk, *cmdBuffer);
    530 
    531 	// Execute Draw
    532 	{
    533 		const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
    534 		VK_CHECK(vk.resetFences(device, 1, &fence.get()));
    535 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
    536 	}
    537 
    538 	// Log inputs
    539 	ctx.getTestContext().getLog()
    540 			<< tcu::TestLog::Message << "Input values: \n"
    541 			<< "1: " << m_testInput << "\n"
    542 			<< tcu::TestLog::EndMessage;
    543 
    544 	// Validate buffer
    545 	if (m_validator.validateBuffer(ctx, **testBuffer))
    546 		return tcu::TestStatus::pass("Everything went OK");
    547 	else
    548 		return tcu::TestStatus::fail("Something went really wrong");
    549 }
    550 
    551 template<typename T>
    552 tcu::TestStatus StorageBufferTestInstance<T>::executeComputeTest(void)
    553 {
    554 	ProtectedContext&						ctx					(m_protectedContext);
    555 	const vk::DeviceInterface&				vk					= ctx.getDeviceInterface();
    556 	const vk::VkDevice						device				= ctx.getDevice();
    557 	const vk::VkQueue						queue				= ctx.getQueue();
    558 	const deUint32							queueFamilyIndex	= ctx.getQueueFamilyIndex();
    559 
    560 	const deUint32							testUniformSize		= sizeof(m_testInput);
    561 	de::UniquePtr<vk::BufferWithMemory>		testUniform			(makeBuffer(ctx,
    562 																		PROTECTION_DISABLED,
    563 																		queueFamilyIndex,
    564 																		testUniformSize,
    565 																		vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
    566 																		 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    567 																		vk::MemoryRequirement::HostVisible));
    568 
    569 	// Set the test input uniform data
    570 	{
    571 		deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize);
    572 		vk::flushMappedMemoryRange(vk, device, testUniform->getAllocation().getMemory(), testUniform->getAllocation().getOffset(), testUniformSize);
    573 	}
    574 
    575 	const deUint32							testBufferSize		= sizeof(ValidationDataStorage<T>);
    576 	de::MovePtr<vk::BufferWithMemory>		testBuffer			(makeBuffer(ctx,
    577 																			PROTECTION_ENABLED,
    578 																			queueFamilyIndex,
    579 																			testBufferSize,
    580 																			vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
    581 																			 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    582 																			vk::MemoryRequirement::Protected));
    583 	de::MovePtr<vk::BufferWithMemory>		testBufferSource	(makeBuffer(ctx,
    584 																			PROTECTION_ENABLED,
    585 																			queueFamilyIndex,
    586 																			testBufferSize,
    587 																			vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
    588 																			 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    589 																			vk::MemoryRequirement::Protected));
    590 
    591 	vk::Unique<vk::VkShaderModule>			testShader			(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0));
    592 
    593 	// Create descriptors
    594 	vk::Unique<vk::VkDescriptorSetLayout>	descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
    595 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
    596 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
    597 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
    598 		.build(vk, device));
    599 	vk::Unique<vk::VkDescriptorPool>		descriptorPool(vk::DescriptorPoolBuilder()
    600 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
    601 		.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
    602 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
    603 		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
    604 	vk::Unique<vk::VkDescriptorSet>			descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
    605 
    606 	// Update descriptor set information
    607 	{
    608 		vk::VkDescriptorBufferInfo	descTestBuffer			= makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize);
    609 		vk::VkDescriptorBufferInfo	descTestUniform			= makeDescriptorBufferInfo(**testUniform, 0, testUniformSize);
    610 		vk::VkDescriptorBufferInfo	descTestBufferSource	= makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize);
    611 
    612 		vk::DescriptorSetUpdateBuilder()
    613 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer)
    614 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform)
    615 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource)
    616 			.update(vk, device);
    617 	}
    618 
    619 
    620 	// Build and execute test
    621 	{
    622 		const vk::Unique<vk::VkFence>		fence				(vk::createFence(vk, device));
    623 		vk::Unique<vk::VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
    624 		vk::Unique<vk::VkPipeline>			SSBOPipeline		(makeComputePipeline(vk, device, *pipelineLayout, *testShader, DE_NULL));
    625 		vk::Unique<vk::VkCommandPool>		cmdPool				(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
    626 		vk::Unique<vk::VkCommandBuffer>		cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
    627 		deUint32							dispatchCount		= (m_testType == SSBO_ATOMIC) ? 4u : 1u;
    628 
    629 		beginCommandBuffer(vk, *cmdBuffer);
    630 
    631 		if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC)
    632 		{
    633 			vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource;
    634 			addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize);
    635 		}
    636 
    637 		vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *SSBOPipeline);
    638 		vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
    639 
    640 		vk.cmdDispatch(*cmdBuffer, dispatchCount, 1u, 1u);
    641 
    642 		endCommandBuffer(vk, *cmdBuffer);
    643 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
    644 	}
    645 
    646 	ctx.getTestContext().getLog()
    647 			<< tcu::TestLog::Message << "Input values: \n"
    648 			<< "1: " << m_testInput << "\n"
    649 			<< tcu::TestLog::EndMessage;
    650 
    651 	// Validate buffer
    652 	if (m_validator.validateBuffer(ctx, **testBuffer))
    653 		return tcu::TestStatus::pass("Everything went OK");
    654 	else
    655 		return tcu::TestStatus::fail("Something went really wrong");
    656 }
    657 
    658 template<typename T>
    659 tcu::TestStatus StorageBufferTestInstance<T>::iterate(void)
    660 {
    661 	switch (m_shaderType)
    662 	{
    663 		case glu::SHADERTYPE_FRAGMENT:	return executeFragmentTest();
    664 		case glu::SHADERTYPE_COMPUTE:	return executeComputeTest();
    665 		default:
    666 			DE_FATAL("Incorrect shader type"); return tcu::TestStatus::fail("");
    667 	}
    668 }
    669 
    670 tcu::TestCaseGroup* createSpecifiedStorageBufferTests (tcu::TestContext&						testCtx,
    671 													   const std::string						groupName,
    672 													   SSBOTestType								testType,
    673 													   const glu::ShaderType					shaderType,
    674 													   const ValidationDataStorage<tcu::UVec4>	testData[],
    675 													   size_t									testCount)
    676 {
    677 	const std::string				testTypeStr		= getSSBOTypeString(testType);
    678 	const std::string				description		= "Storage buffer " + testTypeStr + " tests";
    679 	de::MovePtr<tcu::TestCaseGroup> testGroup		(new tcu::TestCaseGroup(testCtx, groupName.c_str(), description.c_str()));
    680 
    681 	for (size_t ndx = 0; ndx < testCount; ++ndx)
    682 	{
    683 		const std::string name = testTypeStr + "_" + de::toString(ndx + 1);
    684 		testGroup->addChild(new StorageBufferTestCase<tcu::UVec4>(testCtx, testType, shaderType, name.c_str(), testData[ndx].values, testData[ndx]));
    685 	}
    686 
    687 	return testGroup.release();
    688 }
    689 
    690 tcu::TestCaseGroup* createRandomizedBufferTests (tcu::TestContext& testCtx, SSBOTestType testType, const glu::ShaderType shaderType, size_t testCount)
    691 {
    692 	de::Random											rnd				(testCtx.getCommandLine().getBaseSeed());
    693 	std::vector<ValidationDataStorage<tcu::UVec4> >		testData;
    694 	testData.resize(testCount);
    695 
    696 	for (size_t ndx = 0; ndx < testCount; ++ndx)
    697 		testData[ndx].values = tcu::UVec4(rnd.getUint32(), rnd.getUint32(), rnd.getUint32(), rnd.getUint32());
    698 
    699 	return createSpecifiedStorageBufferTests(testCtx, "random", testType, shaderType, testData.data(), testData.size());
    700 }
    701 
    702 tcu::TestCaseGroup* createRWStorageBufferTests (tcu::TestContext&							testCtx,
    703 												const std::string							groupName,
    704 												const std::string							groupDescription,
    705 												SSBOTestType								testType,
    706 												const ValidationDataStorage<tcu::UVec4>		testData[],
    707 												size_t										testCount)
    708 {
    709 	de::MovePtr<tcu::TestCaseGroup> ssboRWTestGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupDescription.c_str()));
    710 
    711 	glu::ShaderType					shaderTypes[] = {
    712 		glu::SHADERTYPE_FRAGMENT,
    713 		glu::SHADERTYPE_COMPUTE
    714 	};
    715 
    716 	for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx)
    717 	{
    718 		const glu::ShaderType				shaderType			= shaderTypes[shaderNdx];
    719 		const std::string					shaderName			= getShaderTypeString(shaderType);
    720 		const std::string					shaderGroupDesc		= "Storage buffer tests for shader type: " + shaderName;
    721 		de::MovePtr<tcu::TestCaseGroup>		testShaderGroup		(new tcu::TestCaseGroup(testCtx, shaderName.c_str(), shaderGroupDesc.c_str()));
    722 
    723 		testShaderGroup->addChild(createSpecifiedStorageBufferTests(testCtx, "static", testType, shaderType, testData, testCount));
    724 		testShaderGroup->addChild(createRandomizedBufferTests(testCtx, testType, shaderType, RANDOM_TEST_COUNT));
    725 		ssboRWTestGroup->addChild(testShaderGroup.release());
    726 	}
    727 
    728 	return ssboRWTestGroup.release();
    729 }
    730 
    731 void calculateAtomicOpData (SSBOAtomicType		type,
    732 							const tcu::UVec4&	inputValue,
    733 							const deUint32		atomicArg,
    734 							std::string&		atomicCall,
    735 							tcu::UVec4&			refValue,
    736 							const deUint32		swapNdx = 0)
    737 {
    738 	switch (type)
    739 	{
    740 		case ATOMIC_ADD:
    741 		{
    742 			refValue	= inputValue + tcu::UVec4(atomicArg);
    743 			atomicCall	= "atomicAdd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    744 			break;
    745 		}
    746 		case ATOMIC_MIN:
    747 		{
    748 			refValue	= tcu::UVec4(std::min(inputValue.x(), atomicArg), std::min(inputValue.y(), atomicArg), std::min(inputValue.z(), atomicArg), std::min(inputValue.w(), atomicArg));
    749 			atomicCall	= "atomicMin(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    750 			break;
    751 		}
    752 		case ATOMIC_MAX:
    753 		{
    754 			refValue	= tcu::UVec4(std::max(inputValue.x(), atomicArg), std::max(inputValue.y(), atomicArg), std::max(inputValue.z(), atomicArg), std::max(inputValue.w(), atomicArg));
    755 			atomicCall	= "atomicMax(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    756 			break;
    757 		}
    758 		case ATOMIC_AND:
    759 		{
    760 			refValue	= tcu::UVec4(inputValue.x() & atomicArg, inputValue.y() & atomicArg, inputValue.z() & atomicArg, inputValue.w() & atomicArg);
    761 			atomicCall	= "atomicAnd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    762 			break;
    763 		}
    764 		case ATOMIC_OR:
    765 		{
    766 			refValue	= tcu::UVec4(inputValue.x() | atomicArg, inputValue.y() | atomicArg, inputValue.z() | atomicArg, inputValue.w() | atomicArg);
    767 			atomicCall	= "atomicOr(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    768 			break;
    769 		}
    770 		case ATOMIC_XOR:
    771 		{
    772 			refValue	= tcu::UVec4(inputValue.x() ^ atomicArg, inputValue.y() ^ atomicArg, inputValue.z() ^ atomicArg, inputValue.w() ^ atomicArg);
    773 			atomicCall	= "atomicXor(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    774 			break;
    775 		}
    776 		case ATOMIC_EXCHANGE:
    777 		{
    778 			refValue	= tcu::UVec4(atomicArg);
    779 			atomicCall	= "atomicExchange(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
    780 			break;
    781 		}
    782 		case ATOMIC_COMPSWAP:
    783 		{
    784 			int			selectedNdx		= swapNdx % 4;
    785 			deUint32	selectedChange	= inputValue[selectedNdx];
    786 
    787 			refValue				= inputValue;
    788 			refValue[selectedNdx]	= atomicArg;
    789 			atomicCall				= "atomicCompSwap(protectedTestResultBuffer[i], " + de::toString(selectedChange) + "u, " + de::toString(atomicArg) + "u);";
    790 			break;
    791 		}
    792 		default: DE_FATAL("Incorrect atomic function type"); break;
    793 	}
    794 
    795 }
    796 
    797 } // anonymous
    798 
    799 tcu::TestCaseGroup* createReadStorageBufferTests (tcu::TestContext& testCtx)
    800 {
    801 	const ValidationDataStorage<tcu::UVec4> testData[] = {
    802 		{ tcu::UVec4(0u, 0u, 0u, 0u) },	{ tcu::UVec4(1u, 0u, 0u, 0u) },
    803 		{ tcu::UVec4(0u, 1u, 0u, 0u) },	{ tcu::UVec4(0u, 0u, 1u, 0u) },
    804 		{ tcu::UVec4(0u, 0u, 0u, 1u) },	{ tcu::UVec4(1u, 1u, 1u, 1u) }
    805 	};
    806 
    807 	return createRWStorageBufferTests(testCtx, "ssbo_read", "Storage Buffer Read Tests", SSBO_READ, testData, DE_LENGTH_OF_ARRAY(testData));
    808 }
    809 
    810 tcu::TestCaseGroup* createWriteStorageBufferTests (tcu::TestContext& testCtx)
    811 {
    812 	const ValidationDataStorage<tcu::UVec4> testData[] = {
    813 		{ tcu::UVec4(0u, 0u, 0u, 0u) }, { tcu::UVec4(1u, 0u, 0u, 0u) },
    814 		{ tcu::UVec4(0u, 1u, 0u, 0u) }, { tcu::UVec4(0u, 0u, 1u, 0u) },
    815 		{ tcu::UVec4(0u, 0u, 0u, 1u) }, { tcu::UVec4(1u, 1u, 1u, 1u) }
    816 	};
    817 
    818 	return createRWStorageBufferTests(testCtx, "ssbo_write", "Storage Buffer Write Tests", SSBO_WRITE, testData, DE_LENGTH_OF_ARRAY(testData));
    819 }
    820 
    821 tcu::TestCaseGroup* createAtomicStorageBufferTests (tcu::TestContext& testctx)
    822 {
    823 	struct {
    824 		const tcu::UVec4	input;
    825 		const deUint32		atomicArg;
    826 		const deUint32		swapNdx;
    827 	}								testData[]	= {
    828 		{ tcu::UVec4(0u,		1u,			2u,			3u),		10u,	0u	},
    829 		{ tcu::UVec4(10u,		20u,		30u,		40u),		3u,		2u	},
    830 		{ tcu::UVec4(800u,		400u,		230u,		999u),		50u,	3u	},
    831 		{ tcu::UVec4(100800u,	233400u,	22230u,		77999u),	800u,	1u	},
    832 	};
    833 
    834 	SSBOAtomicType					testTypes[]	= {
    835 		ATOMIC_ADD,
    836 		ATOMIC_MIN,
    837 		ATOMIC_MAX,
    838 		ATOMIC_AND,
    839 		ATOMIC_OR,
    840 		ATOMIC_XOR,
    841 		ATOMIC_EXCHANGE,
    842 		ATOMIC_COMPSWAP
    843 	};
    844 
    845 	glu::ShaderType					shaderTypes[] = {
    846 		glu::SHADERTYPE_FRAGMENT,
    847 		glu::SHADERTYPE_COMPUTE
    848 	};
    849 
    850 	de::Random						rnd				(testctx.getCommandLine().getBaseSeed());
    851 	de::MovePtr<tcu::TestCaseGroup>	ssboAtomicTests (new tcu::TestCaseGroup(testctx, "ssbo_atomic", "Storage Buffer Atomic Tests"));
    852 
    853 	for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx)
    854 	{
    855 		const glu::ShaderType				shaderType			= shaderTypes[shaderNdx];
    856 		const std::string					shaderName			= getShaderTypeString(shaderType);
    857 		const std::string					shaderDesc			= "Storage Buffer Atomic Tests for shader type: " + shaderName;
    858 		de::MovePtr<tcu::TestCaseGroup>		atomicShaderGroup	(new tcu::TestCaseGroup(testctx, shaderName.c_str(), shaderDesc.c_str()));
    859 
    860 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++typeNdx)
    861 		{
    862 			SSBOAtomicType					atomicType		= testTypes[typeNdx];
    863 			const std::string				atomicTypeStr	= getSSBOAtomicTypeString(atomicType);
    864 			const std::string				atomicDesc		= "Storage Buffer Atomic Tests: " + atomicTypeStr;
    865 
    866 			de::MovePtr<tcu::TestCaseGroup>	staticTests		(new tcu::TestCaseGroup(testctx, "static", (atomicDesc + " with static input").c_str()));
    867 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx)
    868 			{
    869 				const std::string	name		= "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1);
    870 				const tcu::UVec4&	inputValue	= testData[ndx].input;
    871 				const deUint32&		atomicArg	= testData[ndx].atomicArg;
    872 				std::string			atomicCall;
    873 				tcu::UVec4			refValue;
    874 
    875 				calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, testData[ndx].swapNdx);
    876 
    877 				ValidationDataStorage<tcu::UVec4>	validationData	= { refValue };
    878 				staticTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, atomicCall));
    879 			}
    880 
    881 			de::MovePtr<tcu::TestCaseGroup>	randomTests		(new tcu::TestCaseGroup(testctx, "random", (atomicDesc + " with random input").c_str()));
    882 			for (int ndx = 0; ndx < RANDOM_TEST_COUNT; ndx++)
    883 			{
    884 				const std::string					name			= "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1);
    885 				deUint32							atomicArg		= rnd.getUint16();
    886 				tcu::UVec4							inputValue;
    887 				tcu::UVec4							refValue;
    888 				std::string							atomicCall;
    889 
    890 				for (int i = 0; i < 4; i++)
    891 					inputValue[i] = rnd.getUint16();
    892 
    893 				calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, ndx);
    894 
    895 				ValidationDataStorage<tcu::UVec4>	validationData	= { refValue };
    896 				randomTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, atomicCall));
    897 
    898 			}
    899 
    900 			de::MovePtr<tcu::TestCaseGroup>	atomicTests		(new tcu::TestCaseGroup(testctx, atomicTypeStr.c_str(), atomicDesc.c_str()));
    901 			atomicTests->addChild(staticTests.release());
    902 			atomicTests->addChild(randomTests.release());
    903 			atomicShaderGroup->addChild(atomicTests.release());
    904 		}
    905 		ssboAtomicTests->addChild(atomicShaderGroup.release());
    906 	}
    907 
    908 	return ssboAtomicTests.release();
    909 }
    910 
    911 } // ProtectedMem
    912 } // vkt
    913