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