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