• 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 
getShaderTypeString(const glu::ShaderType shaderType)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 
getSSBOAtomicTypeString(SSBOAtomicType type)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 
addBufferCopyCmd(const vk::DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,deUint32 queueFamilyIndex,vk::VkBuffer srcBuffer,vk::VkBuffer dstBuffer,deUint32 copySize)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:
StorageBufferTestCase(tcu::TestContext & testctx,const SSBOTestType testType,const glu::ShaderType shaderType,const char * name,const tcu::UVec4 testInput,ValidationDataStorage<T> validationData,const std::string & extraShader="")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 								}
createInstance(Context & ctx) const223 	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 
~StorageBufferTestCase(void)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>
StorageBufferTestInstance(Context & ctx,const SSBOTestType testType,const glu::ShaderType shaderType,const tcu::UVec4 testInput,const BufferValidator<T> & validator)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>
initPrograms(vk::SourceCollections & programCollection) const255 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>
executeFragmentTest(void)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>
executeComputeTest(void)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>
iterate(void)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 
createSpecifiedStorageBufferTests(tcu::TestContext & testCtx,const std::string groupName,SSBOTestType testType,const glu::ShaderType shaderType,const ValidationDataStorage<tcu::UVec4> testData[],size_t testCount)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 
createRandomizedBufferTests(tcu::TestContext & testCtx,SSBOTestType testType,const glu::ShaderType shaderType,size_t testCount)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 
createRWStorageBufferTests(tcu::TestContext & testCtx,const std::string groupName,const std::string groupDescription,SSBOTestType testType,const ValidationDataStorage<tcu::UVec4> testData[],size_t testCount)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 
calculateAtomicOpData(SSBOAtomicType type,const tcu::UVec4 & inputValue,const deUint32 atomicArg,std::string & atomicCall,tcu::UVec4 & refValue,const deUint32 swapNdx=0)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 
createReadStorageBufferTests(tcu::TestContext & testCtx)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 
createWriteStorageBufferTests(tcu::TestContext & testCtx)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 
createAtomicStorageBufferTests(tcu::TestContext & testctx)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