1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 The Android Open Source Project
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 Memory qualifiers tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktImageQualifiersTests.hpp"
26#include "vktImageLoadStoreTests.hpp"
27#include "vktImageTestsUtil.hpp"
28
29#include "vkDefs.hpp"
30#include "vkImageUtil.hpp"
31#include "vkRef.hpp"
32#include "vkRefUtil.hpp"
33#include "vktTestCase.hpp"
34#include "vktTestCaseUtil.hpp"
35#include "vkPlatform.hpp"
36#include "vkPrograms.hpp"
37#include "vkMemUtil.hpp"
38#include "vkBuilderUtil.hpp"
39#include "vkQueryUtil.hpp"
40#include "vkTypeUtil.hpp"
41
42#include "deDefs.hpp"
43#include "deStringUtil.hpp"
44#include "deUniquePtr.hpp"
45
46#include "tcuImageCompare.hpp"
47#include "tcuTexture.hpp"
48#include "tcuTextureUtil.hpp"
49#include "tcuVectorType.hpp"
50
51using namespace vk;
52
53namespace vkt
54{
55namespace image
56{
57namespace
58{
59
60static const tcu::UVec3		g_localWorkGroupSizeBase	= tcu::UVec3(8, 8, 2);
61static const deInt32		g_ShaderReadOffsetsX[4]		= { 1, 4, 7, 10 };
62static const deInt32		g_ShaderReadOffsetsY[4]		= { 2, 5, 8, 11 };
63static const deInt32		g_ShaderReadOffsetsZ[4]		= { 3, 6, 9, 12 };
64static const char* const	g_ShaderReadOffsetsXStr		= "int[]( 1, 4, 7, 10 )";
65static const char* const	g_ShaderReadOffsetsYStr		= "int[]( 2, 5, 8, 11 )";
66static const char* const	g_ShaderReadOffsetsZStr		= "int[]( 3, 6, 9, 12 )";
67
68const tcu::UVec3 getLocalWorkGroupSize (const ImageType imageType, const tcu::UVec3& imageSize)
69{
70	const tcu::UVec3 computeGridSize	= getShaderGridSize(imageType, imageSize);
71
72	const tcu::UVec3 localWorkGroupSize = tcu::UVec3(de::min(g_localWorkGroupSizeBase.x(), computeGridSize.x()),
73													 de::min(g_localWorkGroupSizeBase.y(), computeGridSize.y()),
74													 de::min(g_localWorkGroupSizeBase.z(), computeGridSize.z()));
75	return localWorkGroupSize;
76}
77
78const tcu::UVec3 getNumWorkGroups (const ImageType imageType, const tcu::UVec3& imageSize)
79{
80	const tcu::UVec3 computeGridSize	= getShaderGridSize(imageType, imageSize);
81	const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(imageType, imageSize);
82
83	return computeGridSize / localWorkGroupSize;
84}
85
86tcu::ConstPixelBufferAccess getLayerOrSlice (const ImageType					imageType,
87											 const tcu::ConstPixelBufferAccess&	access,
88											 const deUint32						layer)
89{
90	switch (imageType)
91	{
92		case IMAGE_TYPE_1D:
93		case IMAGE_TYPE_2D:
94		case IMAGE_TYPE_BUFFER:
95			DE_ASSERT(layer == 0);
96			return access;
97
98		case IMAGE_TYPE_1D_ARRAY:
99			return tcu::getSubregion(access, 0, layer, access.getWidth(), 1);
100
101		case IMAGE_TYPE_2D_ARRAY:
102		case IMAGE_TYPE_3D:
103		case IMAGE_TYPE_CUBE:
104		case IMAGE_TYPE_CUBE_ARRAY:
105			return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1);
106
107		default:
108			DE_FATAL("Unknown image type");
109			return tcu::ConstPixelBufferAccess();
110	}
111}
112
113bool comparePixelBuffers (tcu::TestContext&						testCtx,
114						  const ImageType						imageType,
115						  const tcu::UVec3&						imageSize,
116						  const tcu::TextureFormat&				format,
117						  const tcu::ConstPixelBufferAccess&	reference,
118						  const tcu::ConstPixelBufferAccess&	result)
119{
120	DE_ASSERT(reference.getFormat() == result.getFormat());
121	DE_ASSERT(reference.getSize() == result.getSize());
122
123	const bool		 intFormat			= isIntFormat(mapTextureFormat(format)) || isUintFormat(mapTextureFormat(format));
124	deUint32		 passedLayers		= 0;
125
126	for (deUint32 layerNdx = 0; layerNdx < getNumLayers(imageType, imageSize); ++layerNdx)
127	{
128		const std::string comparisonName = "Comparison" + de::toString(layerNdx);
129
130		std::string comparisonDesc = "Image Comparison, ";
131		switch (imageType)
132		{
133			case IMAGE_TYPE_3D:
134				comparisonDesc = comparisonDesc + "slice " + de::toString(layerNdx);
135				break;
136
137			case IMAGE_TYPE_CUBE:
138			case IMAGE_TYPE_CUBE_ARRAY:
139				comparisonDesc = comparisonDesc + "face " + de::toString(layerNdx % 6) + ", cube " + de::toString(layerNdx / 6);
140				break;
141
142			default:
143				comparisonDesc = comparisonDesc + "layer " + de::toString(layerNdx);
144				break;
145		}
146
147		const tcu::ConstPixelBufferAccess refLayer		= getLayerOrSlice(imageType, reference, layerNdx);
148		const tcu::ConstPixelBufferAccess resultLayer	= getLayerOrSlice(imageType, result, layerNdx);
149
150		bool ok = false;
151		if (intFormat)
152			ok = tcu::intThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
153		else
154			ok = tcu::floatThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
155
156		if (ok)
157			++passedLayers;
158	}
159
160	return passedLayers == getNumLayers(imageType, imageSize);
161}
162
163const std::string getCoordStr (const ImageType		imageType,
164							   const std::string&	x,
165							   const std::string&	y,
166							   const std::string&	z)
167{
168	switch (imageType)
169	{
170		case IMAGE_TYPE_1D:
171		case IMAGE_TYPE_BUFFER:
172			return x;
173
174		case IMAGE_TYPE_1D_ARRAY:
175		case IMAGE_TYPE_2D:
176			return "ivec2(" + x + "," + y + ")";
177
178		case IMAGE_TYPE_2D_ARRAY:
179		case IMAGE_TYPE_3D:
180		case IMAGE_TYPE_CUBE:
181		case IMAGE_TYPE_CUBE_ARRAY:
182			return "ivec3(" + x + "," + y + "," + z + ")";
183
184		default:
185			DE_ASSERT(false);
186			return "";
187	}
188}
189
190class MemoryQualifierTestCase : public vkt::TestCase
191{
192public:
193
194	enum Qualifier
195	{
196		QUALIFIER_COHERENT = 0,
197		QUALIFIER_VOLATILE,
198		QUALIFIER_RESTRICT,
199		QUALIFIER_LAST
200	};
201
202								MemoryQualifierTestCase		(tcu::TestContext&			testCtx,
203															 const std::string&			name,
204															 const std::string&			description,
205															 const Qualifier			qualifier,
206															 const ImageType			imageType,
207															 const tcu::UVec3&			imageSize,
208															 const tcu::TextureFormat&	format,
209															 const glu::GLSLVersion		glslVersion);
210
211	virtual						~MemoryQualifierTestCase	(void) {}
212
213	virtual void				initPrograms				(SourceCollections&			programCollection) const;
214	virtual TestInstance*		createInstance				(Context&					context) const;
215
216protected:
217
218	const Qualifier				m_qualifier;
219	const ImageType				m_imageType;
220	const tcu::UVec3			m_imageSize;
221	const tcu::TextureFormat	m_format;
222	const glu::GLSLVersion		m_glslVersion;
223};
224
225MemoryQualifierTestCase::MemoryQualifierTestCase (tcu::TestContext&			testCtx,
226												  const std::string&		name,
227												  const std::string&		description,
228												  const Qualifier			qualifier,
229												  const ImageType			imageType,
230												  const tcu::UVec3&			imageSize,
231												  const tcu::TextureFormat&	format,
232												  const glu::GLSLVersion	glslVersion)
233	: vkt::TestCase(testCtx, name, description)
234	, m_qualifier(qualifier)
235	, m_imageType(imageType)
236	, m_imageSize(imageSize)
237	, m_format(format)
238	, m_glslVersion(glslVersion)
239{
240}
241
242void MemoryQualifierTestCase::initPrograms (SourceCollections& programCollection) const
243{
244	const char* const	versionDecl			= glu::getGLSLVersionDeclaration(m_glslVersion);
245
246	const char* const	qualifierName		= m_qualifier == QUALIFIER_COHERENT ? "coherent"
247											: m_qualifier == QUALIFIER_VOLATILE ? "volatile"
248											: DE_NULL;
249
250	const bool			uintFormat			= isUintFormat(mapTextureFormat(m_format));
251	const bool			intFormat			= isIntFormat(mapTextureFormat(m_format));
252	const std::string	colorVecTypeName	= std::string(uintFormat ? "u"	: intFormat ? "i" : "") + "vec4";
253	const std::string	colorScalarTypeName = std::string(uintFormat ? "uint" : intFormat ? "int" : "float");
254	const std::string	invocationCoord		= getCoordStr(m_imageType, "gx", "gy", "gz");
255	const std::string	shaderImageFormat	= getShaderImageFormatQualifier(m_format);
256	const std::string	shaderImageType		= getShaderImageType(m_format, m_imageType);
257
258	const tcu::UVec3	localWorkGroupSize	= getLocalWorkGroupSize(m_imageType, m_imageSize);
259	const std::string	localSizeX			= de::toString(localWorkGroupSize.x());
260	const std::string	localSizeY			= de::toString(localWorkGroupSize.y());
261	const std::string	localSizeZ			= de::toString(localWorkGroupSize.z());
262
263	std::ostringstream	programBuffer;
264
265	programBuffer
266		<< versionDecl << "\n"
267		<< "\n"
268		<< "precision highp " << shaderImageType << ";\n"
269		<< "\n"
270		<< "layout (local_size_x = " << localSizeX << ", local_size_y = " << localSizeY << ", local_size_z = " + localSizeZ << ") in;\n"
271		<< "layout (" << shaderImageFormat << ", binding=0) " << qualifierName << " uniform " << shaderImageType << " u_image;\n"
272		<< "void main (void)\n"
273		<< "{\n"
274		<< "	int gx = int(gl_GlobalInvocationID.x);\n"
275		<< "	int gy = int(gl_GlobalInvocationID.y);\n"
276		<< "	int gz = int(gl_GlobalInvocationID.z);\n"
277		<< "	imageStore(u_image, " << invocationCoord << ", " << colorVecTypeName << "(gx^gy^gz));\n"
278		<< "\n"
279		<< "	memoryBarrier();\n"
280		<< "	barrier();\n"
281		<< "\n"
282		<< "	" << colorScalarTypeName << " sum = " << colorScalarTypeName << "(0);\n"
283		<< "	int groupBaseX = gx/" << localSizeX << "*" << localSizeX << ";\n"
284		<< "	int groupBaseY = gy/" << localSizeY << "*" << localSizeY << ";\n"
285		<< "	int groupBaseZ = gz/" << localSizeZ << "*" << localSizeZ << ";\n"
286		<< "	int xOffsets[] = " << g_ShaderReadOffsetsXStr << ";\n"
287		<< "	int yOffsets[] = " << g_ShaderReadOffsetsYStr << ";\n"
288		<< "	int zOffsets[] = " << g_ShaderReadOffsetsZStr << ";\n"
289		<< "	for (int i = 0; i < " << de::toString(DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX)) << "; i++)\n"
290		<< "	{\n"
291		<< "		int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n"
292		<< "		int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n"
293		<< "		int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n"
294		<< "		sum += imageLoad(u_image, " << getCoordStr(m_imageType, "readX", "readY", "readZ") << ").x;\n"
295		<< "	}\n"
296		<< "\n"
297		<< "	memoryBarrier();\n"
298		<< "	barrier();\n"
299		<< "\n"
300		<< "	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
301		<< "}\n";
302
303	programCollection.glslSources.add(m_name) << glu::ComputeSource(programBuffer.str());
304}
305
306class MemoryQualifierInstanceBase : public vkt::TestInstance
307{
308public:
309									MemoryQualifierInstanceBase		(Context&					context,
310																	 const std::string&			name,
311																	 const ImageType			imageType,
312																	 const tcu::UVec3&			imageSize,
313																	 const tcu::TextureFormat&	format);
314
315	virtual							~MemoryQualifierInstanceBase	(void) {};
316
317	virtual tcu::TestStatus			iterate							(void);
318
319	virtual void					prepareResources				(const VkDeviceSize			bufferSizeInBytes) = 0;
320
321	virtual void					prepareDescriptors				(void) = 0;
322
323	virtual void					commandsBeforeCompute			(const VkCommandBuffer		cmdBuffer,
324																	 const VkDeviceSize			bufferSizeInBytes) const = 0;
325
326	virtual void					commandsAfterCompute			(const VkCommandBuffer		cmdBuffer,
327																	 const VkDeviceSize			bufferSizeInBytes) const = 0;
328protected:
329
330	tcu::TextureLevel				generateReferenceImage			(void) const;
331
332	const std::string				m_name;
333	const ImageType					m_imageType;
334	const tcu::UVec3				m_imageSize;
335	const tcu::TextureFormat		m_format;
336
337	de::MovePtr<Buffer>				m_buffer;
338	Move<VkDescriptorPool>			m_descriptorPool;
339	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
340	Move<VkDescriptorSet>			m_descriptorSet;
341};
342
343MemoryQualifierInstanceBase::MemoryQualifierInstanceBase (Context&					context,
344														  const std::string&		name,
345														  const ImageType			imageType,
346														  const tcu::UVec3&			imageSize,
347														  const tcu::TextureFormat&	format)
348	: vkt::TestInstance(context)
349	, m_name(name)
350	, m_imageType(imageType)
351	, m_imageSize(imageSize)
352	, m_format(format)
353{
354}
355
356tcu::TestStatus	MemoryQualifierInstanceBase::iterate (void)
357{
358	const VkDevice			device				= m_context.getDevice();
359	const DeviceInterface&	deviceInterface		= m_context.getDeviceInterface();
360	const VkQueue			queue				= m_context.getUniversalQueue();
361	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
362
363	const VkDeviceSize	bufferSizeInBytes = getNumPixels(m_imageType, m_imageSize) * tcu::getPixelSize(m_format);
364
365	// Prepare resources for the test
366	prepareResources(bufferSizeInBytes);
367
368	// Prepare descriptor sets
369	prepareDescriptors();
370
371	// Create compute shader
372	const vk::Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get(m_name), 0u));
373
374	// Create compute pipeline
375	const vk::Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, device, *m_descriptorSetLayout));
376	const vk::Unique<VkPipeline> pipeline(makeComputePipeline(deviceInterface, device, *pipelineLayout, *shaderModule));
377
378	// Create command buffer
379	const Unique<VkCommandPool> cmdPool(makeCommandPool(deviceInterface, device, queueFamilyIndex));
380	const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(deviceInterface, device, *cmdPool));
381
382	// Start recording commands
383	beginCommandBuffer(deviceInterface, *cmdBuffer);
384
385	deviceInterface.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
386	deviceInterface.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
387
388	commandsBeforeCompute(*cmdBuffer, bufferSizeInBytes);
389
390	const tcu::UVec3 numGroups = getNumWorkGroups(m_imageType, m_imageSize);
391	deviceInterface.cmdDispatch(*cmdBuffer, numGroups.x(), numGroups.y(), numGroups.z());
392
393	commandsAfterCompute(*cmdBuffer, bufferSizeInBytes);
394
395	endCommandBuffer(deviceInterface, *cmdBuffer);
396
397	// Submit and wait for completion
398	submitCommandsAndWait(deviceInterface, device, queue, *cmdBuffer);
399
400	// Retrieve data from buffer to host memory
401	const Allocation& allocation = m_buffer->getAllocation();
402	invalidateMappedMemoryRange(deviceInterface, device, allocation.getMemory(), allocation.getOffset(), bufferSizeInBytes);
403
404	const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize);
405	tcu::ConstPixelBufferAccess resultPixelBuffer(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z(), allocation.getHostPtr());
406
407	// Create a reference image
408	tcu::TextureLevel referenceImage = generateReferenceImage();
409	tcu::ConstPixelBufferAccess referencePixelBuffer = referenceImage.getAccess();
410
411	// Validate the result
412	if (comparePixelBuffers(m_context.getTestContext(), m_imageType, m_imageSize, m_format, referencePixelBuffer, resultPixelBuffer))
413		return tcu::TestStatus::pass("Passed");
414	else
415		return tcu::TestStatus::fail("Image comparison failed");
416}
417
418tcu::TextureLevel MemoryQualifierInstanceBase::generateReferenceImage (void) const
419{
420	// Generate a reference image data using the storage format
421	const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize);
422
423	tcu::TextureLevel base(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z());
424	tcu::PixelBufferAccess baseAccess = base.getAccess();
425
426	tcu::TextureLevel reference(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z());
427	tcu::PixelBufferAccess referenceAccess = reference.getAccess();
428
429	for (deInt32 z = 0; z < baseAccess.getDepth(); ++z)
430		for (deInt32 y = 0; y < baseAccess.getHeight(); ++y)
431			for (deInt32 x = 0; x < baseAccess.getWidth(); ++x)
432			{
433				baseAccess.setPixel(tcu::IVec4(x^y^z), x, y, z);
434			}
435
436	const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(m_imageType, m_imageSize);
437
438	for (deInt32 z = 0; z < referenceAccess.getDepth(); ++z)
439		for (deInt32 y = 0; y < referenceAccess.getHeight(); ++y)
440			for (deInt32 x = 0; x < referenceAccess.getWidth(); ++x)
441			{
442				const deInt32	groupBaseX	= x / localWorkGroupSize.x() * localWorkGroupSize.x();
443				const deInt32	groupBaseY	= y / localWorkGroupSize.y() * localWorkGroupSize.y();
444				const deInt32	groupBaseZ	= z / localWorkGroupSize.z() * localWorkGroupSize.z();
445				deInt32			sum			= 0;
446
447				for (deInt32 i = 0; i < DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX); i++)
448				{
449					sum += baseAccess.getPixelInt(
450						groupBaseX + (x + g_ShaderReadOffsetsX[i]) % localWorkGroupSize.x(),
451						groupBaseY + (y + g_ShaderReadOffsetsY[i]) % localWorkGroupSize.y(),
452						groupBaseZ + (z + g_ShaderReadOffsetsZ[i]) % localWorkGroupSize.z()).x();
453				}
454
455				referenceAccess.setPixel(tcu::IVec4(sum), x, y, z);
456			}
457
458	return reference;
459}
460
461class MemoryQualifierInstanceImage : public MemoryQualifierInstanceBase
462{
463public:
464						MemoryQualifierInstanceImage	(Context&					context,
465														 const std::string&			name,
466														 const ImageType			imageType,
467														 const tcu::UVec3&			imageSize,
468														 const tcu::TextureFormat&	format)
469							: MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {}
470
471	virtual				~MemoryQualifierInstanceImage	(void) {};
472
473	virtual void		prepareResources				(const VkDeviceSize			bufferSizeInBytes);
474
475	virtual void		prepareDescriptors				(void);
476
477	virtual void		commandsBeforeCompute			(const VkCommandBuffer		cmdBuffer,
478														 const VkDeviceSize			bufferSizeInBytes) const;
479
480	virtual void		commandsAfterCompute			(const VkCommandBuffer		cmdBuffer,
481														 const VkDeviceSize			bufferSizeInBytes) const;
482protected:
483
484	de::MovePtr<Image>	m_image;
485	Move<VkImageView>	m_imageView;
486};
487
488void MemoryQualifierInstanceImage::prepareResources (const VkDeviceSize bufferSizeInBytes)
489{
490	const VkDevice			device			= m_context.getDevice();
491	const DeviceInterface&	deviceInterface = m_context.getDeviceInterface();
492	Allocator&				allocator		= m_context.getDefaultAllocator();
493
494	// Create image
495	const VkImageCreateInfo imageCreateInfo =
496	{
497		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType;
498		DE_NULL,														// const void*				pNext;
499		m_imageType == IMAGE_TYPE_CUBE ||
500		m_imageType	== IMAGE_TYPE_CUBE_ARRAY
501		? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u,	// VkImageCreateFlags		flags;
502		mapImageType(m_imageType),										// VkImageType				imageType;
503		mapTextureFormat(m_format),										// VkFormat					format;
504		makeExtent3D(getLayerSize(m_imageType, m_imageSize)),			// VkExtent3D				extent;
505		1u,																// deUint32					mipLevels;
506		getNumLayers(m_imageType, m_imageSize),							// deUint32					arrayLayers;
507		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits	samples;
508		VK_IMAGE_TILING_OPTIMAL,										// VkImageTiling			tiling;
509		VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT,	// VkImageUsageFlags		usage;
510		VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode;
511		0u,																// deUint32					queueFamilyIndexCount;
512		DE_NULL,														// const deUint32*			pQueueFamilyIndices;
513		VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout			initialLayout;
514	};
515
516	m_image = de::MovePtr<Image>(new Image(deviceInterface, device, allocator, imageCreateInfo, MemoryRequirement::Any));
517
518	// Create imageView
519	const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
520	m_imageView = makeImageView(deviceInterface, device, m_image->get(), mapImageViewType(m_imageType), mapTextureFormat(m_format), subresourceRange);
521
522	// Create a buffer to store shader output (copied from image data)
523	const VkBufferCreateInfo	bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
524	m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
525}
526
527void MemoryQualifierInstanceImage::prepareDescriptors (void)
528{
529	const VkDevice			device			= m_context.getDevice();
530	const DeviceInterface&	deviceInterface = m_context.getDeviceInterface();
531
532	// Create descriptor pool
533	m_descriptorPool =
534		DescriptorPoolBuilder()
535		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
536		.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
537
538	// Create descriptor set layout
539	m_descriptorSetLayout =
540		DescriptorSetLayoutBuilder()
541		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
542		.build(deviceInterface, device);
543
544	// Allocate descriptor set
545	m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout);
546
547	// Set the bindings
548	const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
549
550	DescriptorSetUpdateBuilder()
551		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
552		.update(deviceInterface, device);
553}
554
555void MemoryQualifierInstanceImage::commandsBeforeCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
556{
557	DE_UNREF(bufferSizeInBytes);
558
559	const DeviceInterface&			deviceInterface	 = m_context.getDeviceInterface();
560	const VkImageSubresourceRange	subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
561
562	const VkImageMemoryBarrier imageLayoutBarrier
563		= makeImageMemoryBarrier(0u,
564								 VK_ACCESS_SHADER_READ_BIT,
565								 VK_IMAGE_LAYOUT_UNDEFINED,
566								 VK_IMAGE_LAYOUT_GENERAL,
567								 m_image->get(),
568								 subresourceRange);
569
570	deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier);
571}
572
573void MemoryQualifierInstanceImage::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
574{
575	const DeviceInterface&			deviceInterface	 = m_context.getDeviceInterface();
576	const VkImageSubresourceRange	subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
577
578	const VkImageMemoryBarrier imagePreCopyBarrier
579		= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT,
580								 VK_ACCESS_TRANSFER_READ_BIT,
581								 VK_IMAGE_LAYOUT_GENERAL,
582								 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
583								 m_image->get(),
584								 subresourceRange);
585
586	deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imagePreCopyBarrier);
587
588	const VkBufferImageCopy copyParams = makeBufferImageCopy(makeExtent3D(getLayerSize(m_imageType, m_imageSize)), getNumLayers(m_imageType, m_imageSize));
589	deviceInterface.cmdCopyImageToBuffer(cmdBuffer, m_image->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer->get(), 1u, &copyParams);
590
591	const VkBufferMemoryBarrier bufferPostCopyBarrier
592		= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
593								  VK_ACCESS_HOST_READ_BIT,
594								  m_buffer->get(),
595								  0ull,
596								  bufferSizeInBytes);
597
598	deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferPostCopyBarrier, 0u, DE_NULL);
599}
600
601class MemoryQualifierInstanceBuffer : public MemoryQualifierInstanceBase
602{
603public:
604						MemoryQualifierInstanceBuffer	(Context&					context,
605														 const std::string&			name,
606														 const ImageType			imageType,
607														 const tcu::UVec3&			imageSize,
608														 const tcu::TextureFormat&	format)
609							: MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {}
610
611	virtual				~MemoryQualifierInstanceBuffer	(void) {};
612
613	virtual void		prepareResources				(const VkDeviceSize			bufferSizeInBytes);
614
615	virtual void		prepareDescriptors				(void);
616
617	virtual void		commandsBeforeCompute			(const VkCommandBuffer,
618														 const VkDeviceSize) const {}
619
620	virtual void		commandsAfterCompute			(const VkCommandBuffer		cmdBuffer,
621														 const VkDeviceSize			bufferSizeInBytes) const;
622protected:
623
624	Move<VkBufferView>	m_bufferView;
625};
626
627void MemoryQualifierInstanceBuffer::prepareResources (const VkDeviceSize bufferSizeInBytes)
628{
629	const VkDevice			device			= m_context.getDevice();
630	const DeviceInterface&	deviceInterface = m_context.getDeviceInterface();
631	Allocator&				allocator		= m_context.getDefaultAllocator();
632
633	// Create a buffer to store shader output
634	const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
635	m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
636
637	m_bufferView = makeBufferView(deviceInterface, device, m_buffer->get(), mapTextureFormat(m_format), 0ull, bufferSizeInBytes);
638}
639
640void MemoryQualifierInstanceBuffer::prepareDescriptors (void)
641{
642	const VkDevice			device			= m_context.getDevice();
643	const DeviceInterface&	deviceInterface = m_context.getDeviceInterface();
644
645	// Create descriptor pool
646	m_descriptorPool =
647		DescriptorPoolBuilder()
648		.addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
649		.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
650
651	// Create descriptor set layout
652	m_descriptorSetLayout =
653		DescriptorSetLayoutBuilder()
654		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
655		.build(deviceInterface, device);
656
657	// Allocate descriptor set
658	m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout);
659
660	// Set the bindings
661	DescriptorSetUpdateBuilder()
662		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
663		.update(deviceInterface, device);
664}
665
666void MemoryQualifierInstanceBuffer::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
667{
668	const DeviceInterface&	deviceInterface = m_context.getDeviceInterface();
669
670	const VkBufferMemoryBarrier shaderWriteBarrier
671		= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT,
672								  VK_ACCESS_HOST_READ_BIT,
673								  m_buffer->get(),
674								  0ull,
675								  bufferSizeInBytes);
676
677	deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
678}
679
680TestInstance* MemoryQualifierTestCase::createInstance (Context& context) const
681{
682	if ( m_imageType == IMAGE_TYPE_BUFFER )
683		return new MemoryQualifierInstanceBuffer(context, m_name, m_imageType, m_imageSize, m_format);
684	else
685		return new MemoryQualifierInstanceImage(context, m_name, m_imageType, m_imageSize, m_format);
686}
687
688} // anonymous ns
689
690tcu::TestCaseGroup* createImageQualifiersTests (tcu::TestContext& testCtx)
691{
692	de::MovePtr<tcu::TestCaseGroup> imageQualifiersTests(new tcu::TestCaseGroup(testCtx, "qualifiers", "Coherent, volatile and restrict"));
693
694	struct ImageParams
695	{
696		ImageParams(const ImageType imageType, const tcu::UVec3& imageSize)
697			: m_imageType	(imageType)
698			, m_imageSize	(imageSize)
699		{
700		}
701		ImageType	m_imageType;
702		tcu::UVec3	m_imageSize;
703	};
704
705	static const ImageParams imageParamsArray[] =
706	{
707		ImageParams(IMAGE_TYPE_1D,			tcu::UVec3(64u, 1u,  1u)),
708		ImageParams(IMAGE_TYPE_1D_ARRAY,	tcu::UVec3(64u, 1u,  8u)),
709		ImageParams(IMAGE_TYPE_2D,			tcu::UVec3(64u, 64u, 1u)),
710		ImageParams(IMAGE_TYPE_2D_ARRAY,	tcu::UVec3(64u, 64u, 8u)),
711		ImageParams(IMAGE_TYPE_3D,			tcu::UVec3(64u, 64u, 8u)),
712		ImageParams(IMAGE_TYPE_CUBE,		tcu::UVec3(64u, 64u, 1u)),
713		ImageParams(IMAGE_TYPE_CUBE_ARRAY,	tcu::UVec3(64u, 64u, 2u)),
714		ImageParams(IMAGE_TYPE_BUFFER,		tcu::UVec3(64u, 1u,  1u))
715	};
716
717	static const tcu::TextureFormat formats[] =
718	{
719		tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT),
720		tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32),
721		tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT32),
722	};
723
724	for (deUint32 qualifierI = 0; qualifierI < MemoryQualifierTestCase::QUALIFIER_LAST; ++qualifierI)
725	{
726		const MemoryQualifierTestCase::Qualifier	memoryQualifier		= (MemoryQualifierTestCase::Qualifier)qualifierI;
727		const char* const							memoryQualifierName =
728			memoryQualifier == MemoryQualifierTestCase::QUALIFIER_COHERENT ? "coherent" :
729			memoryQualifier == MemoryQualifierTestCase::QUALIFIER_VOLATILE ? "volatile" :
730			memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT ? "restrict" :
731			DE_NULL;
732
733		de::MovePtr<tcu::TestCaseGroup> qualifierGroup(new tcu::TestCaseGroup(testCtx, memoryQualifierName, ""));
734
735		for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParamsArray); imageTypeNdx++)
736		{
737			const ImageType		imageType = imageParamsArray[imageTypeNdx].m_imageType;
738			const tcu::UVec3	imageSize = imageParamsArray[imageTypeNdx].m_imageSize;
739
740			if (memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT)
741			{
742				de::MovePtr<TestCase> restrictCase = createImageQualifierRestrictCase(testCtx, imageType, getImageTypeName(imageType));
743				qualifierGroup->addChild(restrictCase.release());
744			}
745			else
746			{
747				for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
748				{
749					const tcu::TextureFormat&	format		= formats[formatNdx];
750					const std::string			formatName	= getShaderImageFormatQualifier(formats[formatNdx]);
751
752					qualifierGroup->addChild(
753						new MemoryQualifierTestCase(testCtx, getImageTypeName(imageType) + std::string("_") + formatName,
754						"", memoryQualifier, imageType, imageSize, format, glu::GLSL_VERSION_440));
755				}
756			}
757		}
758
759		imageQualifiersTests->addChild(qualifierGroup.release());
760	}
761
762	return imageQualifiersTests.release();
763}
764
765} // image
766} // vkt
767