1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Buffer and image memory requirements tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "vktMemoryRequirementsTests.hpp"
25#include "vktTestCaseUtil.hpp"
26#include "vktTestGroupUtil.hpp"
27
28#include "vkDefs.hpp"
29#include "vkRef.hpp"
30#include "vkRefUtil.hpp"
31#include "vkMemUtil.hpp"
32#include "vkQueryUtil.hpp"
33#include "vkStrUtil.hpp"
34#include "vkTypeUtil.hpp"
35
36#include "deUniquePtr.hpp"
37#include "deStringUtil.hpp"
38
39#include "tcuResultCollector.hpp"
40#include "tcuTestLog.hpp"
41
42namespace vkt
43{
44namespace memory
45{
46namespace
47{
48using namespace vk;
49using de::MovePtr;
50
51Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize size, const VkBufferCreateFlags flags, const VkBufferUsageFlags usage)
52{
53	const VkBufferCreateInfo createInfo =
54	{
55		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType        sType;
56		DE_NULL,									// const void*            pNext;
57		flags,										// VkBufferCreateFlags    flags;
58		size,										// VkDeviceSize           size;
59		usage,										// VkBufferUsageFlags     usage;
60		VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode          sharingMode;
61		0u,											// uint32_t               queueFamilyIndexCount;
62		DE_NULL,									// const uint32_t*        pQueueFamilyIndices;
63	};
64	return createBuffer(vk, device, &createInfo);
65}
66
67//! Get an index of each set bit, starting from the least significant bit.
68std::vector<deUint32> bitsToIndices (deUint32 bits)
69{
70	std::vector<deUint32> indices;
71	for (deUint32 i = 0u; bits != 0u; ++i, bits >>= 1)
72	{
73		if (bits & 1u)
74			indices.push_back(i);
75	}
76	return indices;
77}
78
79VkMemoryRequirements getBufferMemoryRequirements (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize size, const VkBufferCreateFlags flags, const VkBufferUsageFlags usage)
80{
81	const Unique<VkBuffer> buffer(makeBuffer(vk, device, size, flags, usage));
82	return getBufferMemoryRequirements(vk, device, *buffer);
83}
84
85template<typename T>
86T nextEnum (T value)
87{
88	return static_cast<T>(static_cast<deUint32>(value) + 1);
89}
90
91template<typename T>
92T nextFlag (T value)
93{
94	if (value)
95		return static_cast<T>(static_cast<deUint32>(value) << 1);
96	else
97		return static_cast<T>(1);
98}
99
100template<typename T>
101T nextFlagExcluding (T value, T excludedFlags)
102{
103	deUint32 tmp = static_cast<deUint32>(value);
104	while ((tmp = nextFlag(tmp)) & static_cast<deUint32>(excludedFlags));
105	return static_cast<T>(tmp);
106}
107
108void requireBufferSparseFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkBufferCreateFlags flags)
109{
110	const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
111
112	if ((flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && !features.sparseBinding)
113		TCU_THROW(NotSupportedError, "Feature not supported: sparseBinding");
114
115	if ((flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && !features.sparseResidencyBuffer)
116		TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyBuffer");
117
118	if ((flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && !features.sparseResidencyAliased)
119		TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyAliased");
120}
121
122void verifyBufferRequirements (tcu::ResultCollector&					result,
123							   const VkPhysicalDeviceMemoryProperties&	deviceMemoryProperties,
124							   const VkMemoryRequirements&				requirements,
125							   const VkMemoryRequirements&				allUsageFlagsRequirements,
126							   const VkPhysicalDeviceLimits&			limits,
127							   const VkBufferCreateFlags				bufferFlags,
128							   const VkBufferUsageFlags					usage)
129{
130	if (result.check(requirements.memoryTypeBits != 0, "VkMemoryRequirements memoryTypeBits has no bits set"))
131	{
132		typedef std::vector<deUint32>::const_iterator	IndexIterator;
133		const std::vector<deUint32>						usedMemoryTypeIndices			= bitsToIndices(requirements.memoryTypeBits);
134		bool											deviceLocalMemoryFound			= false;
135		bool											hostVisibleCoherentMemoryFound	= false;
136
137		for (IndexIterator memoryTypeNdx = usedMemoryTypeIndices.begin(); memoryTypeNdx != usedMemoryTypeIndices.end(); ++memoryTypeNdx)
138		{
139			if (*memoryTypeNdx >= deviceMemoryProperties.memoryTypeCount)
140			{
141				result.fail("VkMemoryRequirements memoryTypeBits contains bits for non-existing memory types");
142				continue;
143			}
144
145			const VkMemoryPropertyFlags	memoryPropertyFlags = deviceMemoryProperties.memoryTypes[*memoryTypeNdx].propertyFlags;
146
147			if (memoryPropertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
148				deviceLocalMemoryFound = true;
149
150			if (memoryPropertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
151				hostVisibleCoherentMemoryFound = true;
152
153			result.check((memoryPropertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) == 0u,
154				"Memory type includes VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT");
155		}
156
157		result.check(deIsPowerOfTwo64(static_cast<deUint64>(requirements.alignment)) == DE_TRUE,
158			"VkMemoryRequirements alignment isn't power of two");
159
160		if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT))
161		{
162			result.check(requirements.alignment >= limits.minTexelBufferOffsetAlignment,
163				"VkMemoryRequirements alignment doesn't respect minTexelBufferOffsetAlignment");
164		}
165
166		if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
167		{
168			result.check(requirements.alignment >= limits.minUniformBufferOffsetAlignment,
169				"VkMemoryRequirements alignment doesn't respect minUniformBufferOffsetAlignment");
170		}
171
172		if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
173		{
174			result.check(requirements.alignment >= limits.minStorageBufferOffsetAlignment,
175				"VkMemoryRequirements alignment doesn't respect minStorageBufferOffsetAlignment");
176		}
177
178		result.check(deviceLocalMemoryFound,
179			"None of the required memory types included VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
180
181		result.check((bufferFlags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) || hostVisibleCoherentMemoryFound,
182			"Required memory type doesn't include VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
183
184		result.check((requirements.memoryTypeBits & allUsageFlagsRequirements.memoryTypeBits) == allUsageFlagsRequirements.memoryTypeBits,
185			"Memory type bits aren't a superset of memory type bits for all usage flags combined");
186	}
187}
188
189tcu::TestStatus testBuffer (Context& context, const VkBufferCreateFlags bufferFlags)
190{
191	const DeviceInterface&					vk							= context.getDeviceInterface();
192	const InstanceInterface&				vki							= context.getInstanceInterface();
193	const VkDevice							device						= context.getDevice();
194	const VkPhysicalDevice					physDevice					= context.getPhysicalDevice();
195
196	requireBufferSparseFeatures(vki, physDevice, bufferFlags);
197
198	const VkPhysicalDeviceMemoryProperties	memoryProperties			= getPhysicalDeviceMemoryProperties(vki, physDevice);
199	const VkPhysicalDeviceLimits			limits						= getPhysicalDeviceProperties(vki, physDevice).limits;
200	const VkBufferUsageFlags				allUsageFlags				= static_cast<VkBufferUsageFlags>((VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT << 1) - 1);
201	const VkMemoryRequirements				allUsageFlagsRequirements	= getBufferMemoryRequirements(vk, device, 1024, bufferFlags, allUsageFlags); // doesn't depend on size
202	tcu::TestLog&							log							= context.getTestContext().getLog();
203	bool									allPass						= true;
204
205	const VkDeviceSize sizeCases[] =
206	{
207		1	 * 1024,
208		8    * 1024,
209		64   * 1024,
210		1024 * 1024,
211	};
212
213	for (VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; usage <= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; usage = nextFlag(usage))
214	{
215		deUint32		previousMemoryTypeBits	= 0u;
216		VkDeviceSize	previousAlignment		= 0u;
217
218		log << tcu::TestLog::Message << "Verify a buffer with usage flags: " << de::toString(getBufferUsageFlagsStr(usage)) << tcu::TestLog::EndMessage;
219
220		for (const VkDeviceSize* pSize = sizeCases; pSize < sizeCases + DE_LENGTH_OF_ARRAY(sizeCases); ++pSize)
221		{
222			log << tcu::TestLog::Message << "- size " << *pSize << " bytes" << tcu::TestLog::EndMessage;
223
224			const VkMemoryRequirements	requirements	= getBufferMemoryRequirements(vk, device, *pSize, bufferFlags, usage);
225			tcu::ResultCollector		result			(log, "ERROR: ");
226
227			// Check:
228			// - requirements for a particular buffer usage
229			// - memoryTypeBits are a subset of bits for requirements with all usage flags combined
230			verifyBufferRequirements(result, memoryProperties, requirements, allUsageFlagsRequirements, limits, bufferFlags, usage);
231
232			// Check that for the same usage and create flags:
233			// - memoryTypeBits are the same
234			// - alignment is the same
235			if (pSize > sizeCases)
236			{
237				result.check(requirements.memoryTypeBits == previousMemoryTypeBits,
238					"memoryTypeBits differ from the ones in the previous buffer size");
239
240				result.check(requirements.alignment == previousAlignment,
241					"alignment differs from the one in the previous buffer size");
242			}
243
244			if (result.getResult() != QP_TEST_RESULT_PASS)
245				allPass = false;
246
247			previousMemoryTypeBits	= requirements.memoryTypeBits;
248			previousAlignment		= requirements.alignment;
249		}
250
251		if (!allPass)
252			break;
253	}
254
255	return allPass ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some memory requirements were incorrect");
256}
257
258void requireImageSparseFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkImageCreateFlags createFlags)
259{
260	const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
261
262	if ((createFlags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) && !features.sparseBinding)
263		TCU_THROW(NotSupportedError, "Feature not supported: sparseBinding");
264
265	if ((createFlags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) && !(features.sparseResidencyImage2D || features.sparseResidencyImage3D))
266		TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyImage (2D and 3D)");
267
268	if ((createFlags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && !features.sparseResidencyAliased)
269		TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyAliased");
270}
271
272bool imageUsageMatchesFormatFeatures (const VkImageUsageFlags usage, const VkFormatFeatureFlags featureFlags)
273{
274	if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) && (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
275		return true;
276	if ((usage & VK_IMAGE_USAGE_STORAGE_BIT) && (featureFlags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
277		return true;
278	if ((usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) && (featureFlags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
279		return true;
280	if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && (featureFlags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
281		return true;
282
283	return false;
284}
285
286//! This catches both invalid as well as legal but unsupported combinations of image parameters
287bool isImageSupported (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkImageCreateInfo& info)
288{
289	DE_ASSERT(info.extent.width >= 1u && info.extent.height >= 1u && info.extent.depth >= 1u);
290
291	if (info.imageType == VK_IMAGE_TYPE_1D)
292	{
293		DE_ASSERT(info.extent.height == 1u && info.extent.depth == 1u);
294	}
295	else if (info.imageType == VK_IMAGE_TYPE_2D)
296	{
297		DE_ASSERT(info.extent.depth == 1u);
298
299		if (info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
300		{
301			DE_ASSERT(info.extent.width == info.extent.height);
302			DE_ASSERT(info.arrayLayers >= 6u && (info.arrayLayers % 6u) == 0u);
303		}
304	}
305
306	if ((info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && info.imageType != VK_IMAGE_TYPE_2D)
307		return false;
308
309	if ((info.samples != VK_SAMPLE_COUNT_1_BIT) &&
310		(info.imageType != VK_IMAGE_TYPE_2D || (info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) || info.tiling != VK_IMAGE_TILING_OPTIMAL || info.mipLevels > 1u))
311		return false;
312
313	if ((info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) &&
314		(info.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0u)
315		return false;
316
317	const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
318
319	if (info.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)
320	{
321		DE_ASSERT(info.tiling == VK_IMAGE_TILING_OPTIMAL);
322
323		if (info.imageType == VK_IMAGE_TYPE_2D && !features.sparseResidencyImage2D)
324			return false;
325		if (info.imageType == VK_IMAGE_TYPE_3D && !features.sparseResidencyImage3D)
326			return false;
327		if (info.samples == VK_SAMPLE_COUNT_2_BIT && !features.sparseResidency2Samples)
328			return false;
329		if (info.samples == VK_SAMPLE_COUNT_4_BIT && !features.sparseResidency4Samples)
330			return false;
331		if (info.samples == VK_SAMPLE_COUNT_8_BIT && !features.sparseResidency8Samples)
332			return false;
333		if (info.samples == VK_SAMPLE_COUNT_16_BIT && !features.sparseResidency16Samples)
334			return false;
335		if (info.samples == VK_SAMPLE_COUNT_32_BIT || info.samples == VK_SAMPLE_COUNT_64_BIT)
336			return false;
337	}
338
339	if (info.samples != VK_SAMPLE_COUNT_1_BIT && (info.usage & VK_IMAGE_USAGE_STORAGE_BIT) && !features.shaderStorageImageMultisample)
340		return false;
341
342	switch (info.format)
343	{
344		case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
345		case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
346		case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
347		case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
348		case VK_FORMAT_BC2_UNORM_BLOCK:
349		case VK_FORMAT_BC2_SRGB_BLOCK:
350		case VK_FORMAT_BC3_UNORM_BLOCK:
351		case VK_FORMAT_BC3_SRGB_BLOCK:
352		case VK_FORMAT_BC4_UNORM_BLOCK:
353		case VK_FORMAT_BC4_SNORM_BLOCK:
354		case VK_FORMAT_BC5_UNORM_BLOCK:
355		case VK_FORMAT_BC5_SNORM_BLOCK:
356		case VK_FORMAT_BC6H_UFLOAT_BLOCK:
357		case VK_FORMAT_BC6H_SFLOAT_BLOCK:
358		case VK_FORMAT_BC7_UNORM_BLOCK:
359		case VK_FORMAT_BC7_SRGB_BLOCK:
360			if (!features.textureCompressionBC)
361				return false;
362			break;
363
364		case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
365		case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
366		case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
367		case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
368		case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
369		case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
370		case VK_FORMAT_EAC_R11_UNORM_BLOCK:
371		case VK_FORMAT_EAC_R11_SNORM_BLOCK:
372		case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
373		case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
374			if (!features.textureCompressionETC2)
375				return false;
376			break;
377
378		case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
379		case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
380		case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
381		case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
382		case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
383		case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
384		case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
385		case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
386		case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
387		case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
388		case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
389		case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
390		case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
391		case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
392		case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
393		case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
394		case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
395		case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
396		case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
397		case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
398		case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
399		case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
400		case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
401		case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
402		case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
403		case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
404		case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
405		case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
406			if (!features.textureCompressionASTC_LDR)
407				return false;
408			break;
409
410		default:
411			break;
412	}
413
414	const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(vki, physDevice, info.format);
415	const VkFormatFeatureFlags	formatFeatures		= (info.tiling == VK_IMAGE_TILING_LINEAR ? formatProperties.linearTilingFeatures
416																							 : formatProperties.optimalTilingFeatures);
417
418	if (!imageUsageMatchesFormatFeatures(info.usage, formatFeatures))
419		return false;
420
421	VkImageFormatProperties		imageFormatProperties;
422	const VkResult				result				= vki.getPhysicalDeviceImageFormatProperties(
423														physDevice, info.format, info.imageType, info.tiling, info.usage, info.flags, &imageFormatProperties);
424
425	if (result == VK_SUCCESS)
426	{
427		if (info.arrayLayers > imageFormatProperties.maxArrayLayers)
428			return false;
429		if (info.mipLevels > imageFormatProperties.maxMipLevels)
430			return false;
431		if ((info.samples & imageFormatProperties.sampleCounts) == 0u)
432			return false;
433	}
434
435	return result == VK_SUCCESS;
436}
437
438VkExtent3D makeExtentForImage (const VkImageType imageType)
439{
440	VkExtent3D extent = { 64u, 64u, 4u };
441
442	if (imageType == VK_IMAGE_TYPE_1D)
443		extent.height = extent.depth = 1u;
444	else if (imageType == VK_IMAGE_TYPE_2D)
445		extent.depth = 1u;
446
447	return extent;
448}
449
450bool isFormatMatchingAspect (const VkFormat format, const VkImageAspectFlags aspect)
451{
452	DE_ASSERT(aspect == VK_IMAGE_ASPECT_COLOR_BIT || aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
453
454	// D/S formats are laid out next to each other in the enum
455	const bool isDepthStencilFormat = (format >= VK_FORMAT_D16_UNORM && format <= VK_FORMAT_D32_SFLOAT_S8_UINT);
456
457	return (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == isDepthStencilFormat;
458}
459
460void verifyImageRequirements (tcu::ResultCollector&						result,
461							  const VkPhysicalDeviceMemoryProperties&	deviceMemoryProperties,
462							  const VkMemoryRequirements&				requirements,
463							  const VkImageCreateInfo&					imageInfo)
464{
465	if (result.check(requirements.memoryTypeBits != 0, "VkMemoryRequirements memoryTypeBits has no bits set"))
466	{
467		typedef std::vector<deUint32>::const_iterator	IndexIterator;
468		const std::vector<deUint32>						usedMemoryTypeIndices			= bitsToIndices(requirements.memoryTypeBits);
469		bool											deviceLocalMemoryFound			= false;
470		bool											hostVisibleCoherentMemoryFound	= false;
471
472		for (IndexIterator memoryTypeNdx = usedMemoryTypeIndices.begin(); memoryTypeNdx != usedMemoryTypeIndices.end(); ++memoryTypeNdx)
473		{
474			if (*memoryTypeNdx >= deviceMemoryProperties.memoryTypeCount)
475			{
476				result.fail("VkMemoryRequirements memoryTypeBits contains bits for non-existing memory types");
477				continue;
478			}
479
480			const VkMemoryPropertyFlags	memoryPropertyFlags = deviceMemoryProperties.memoryTypes[*memoryTypeNdx].propertyFlags;
481
482			if (memoryPropertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
483				deviceLocalMemoryFound = true;
484
485			if (memoryPropertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
486				hostVisibleCoherentMemoryFound = true;
487
488			if (memoryPropertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
489			{
490				result.check((imageInfo.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0u,
491					"Memory type includes VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT for a non-transient attachment image");
492			}
493		}
494
495		result.check(deIsPowerOfTwo64(static_cast<deUint64>(requirements.alignment)) == DE_TRUE,
496			"VkMemoryRequirements alignment isn't power of two");
497
498		result.check(deviceLocalMemoryFound,
499			"None of the required memory types included VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
500
501		result.check(imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL || hostVisibleCoherentMemoryFound,
502			"Required memory type doesn't include VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
503	}
504}
505
506std::string getImageInfoString (const VkImageCreateInfo& imageInfo)
507{
508	std::ostringstream str;
509
510	switch (imageInfo.imageType)
511	{
512		case VK_IMAGE_TYPE_1D:			str << "1D "; break;
513		case VK_IMAGE_TYPE_2D:			str << "2D "; break;
514		case VK_IMAGE_TYPE_3D:			str << "3D "; break;
515		default:						break;
516	}
517
518	switch (imageInfo.tiling)
519	{
520		case VK_IMAGE_TILING_OPTIMAL:	str << "(optimal) "; break;
521		case VK_IMAGE_TILING_LINEAR:	str << "(linear) "; break;
522		default:						break;
523	}
524
525	str << "extent:[" << imageInfo.extent.width << ", " << imageInfo.extent.height << ", " << imageInfo.extent.depth << "] ";
526	str << imageInfo.format << " ";
527	str << "samples:" << static_cast<deUint32>(imageInfo.samples) << " ";
528	str << "flags:" << static_cast<deUint32>(imageInfo.flags) << " ";
529	str << "usage:" << static_cast<deUint32>(imageInfo.usage) << " ";
530
531	return str.str();
532}
533
534struct ImageParams
535{
536	VkImageCreateFlags		flags;
537	VkImageTiling			tiling;
538	bool					transient;
539};
540
541tcu::TestStatus testImage (Context& context, const ImageParams params)
542{
543	const DeviceInterface&		vk				= context.getDeviceInterface();
544	const InstanceInterface&	vki				= context.getInstanceInterface();
545	const VkDevice				device			= context.getDevice();
546	const VkPhysicalDevice		physDevice		= context.getPhysicalDevice();
547	const VkImageCreateFlags	sparseFlags		= VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT;
548	const VkImageUsageFlags		transientFlags	= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
549
550	requireImageSparseFeatures(vki, physDevice, params.flags);
551
552	const VkPhysicalDeviceMemoryProperties	memoryProperties		= getPhysicalDeviceMemoryProperties(vki, physDevice);
553	const deUint32							notInitializedBits		= ~0u;
554	const VkImageAspectFlags				colorAspect				= VK_IMAGE_ASPECT_COLOR_BIT;
555	const VkImageAspectFlags				depthStencilAspect		= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
556	const VkImageAspectFlags				allAspects[2]			= { colorAspect, depthStencilAspect };
557	tcu::TestLog&							log						= context.getTestContext().getLog();
558	bool									allPass					= true;
559	deUint32								numCheckedImages		= 0u;
560
561	log << tcu::TestLog::Message << "Verify memory requirements for the following parameter combinations:" << tcu::TestLog::EndMessage;
562
563	for (deUint32 loopAspectNdx = 0u; loopAspectNdx < DE_LENGTH_OF_ARRAY(allAspects); ++loopAspectNdx)
564	{
565		const VkImageAspectFlags	aspect					= allAspects[loopAspectNdx];
566		deUint32					previousMemoryTypeBits	= notInitializedBits;
567
568		for (VkFormat loopFormat = VK_FORMAT_R4G4_UNORM_PACK8; loopFormat <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; loopFormat = nextEnum(loopFormat))
569		if  (isFormatMatchingAspect(loopFormat, aspect))
570		{
571			// memoryTypeBits may differ between depth/stencil formats
572			if (aspect == depthStencilAspect)
573				previousMemoryTypeBits = notInitializedBits;
574
575			for (VkImageType			loopImageType	= VK_IMAGE_TYPE_1D;					loopImageType	!= VK_IMAGE_TYPE_LAST;					loopImageType	= nextEnum(loopImageType))
576			for (VkImageCreateFlags		loopCreateFlags	= (VkImageCreateFlags)0;			loopCreateFlags	<= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;	loopCreateFlags	= nextFlagExcluding(loopCreateFlags, sparseFlags))
577			for (VkImageUsageFlags		loopUsageFlags	= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;	loopUsageFlags	<= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;	loopUsageFlags	= nextFlagExcluding(loopUsageFlags, transientFlags))
578			for (VkSampleCountFlagBits	loopSampleCount	= VK_SAMPLE_COUNT_1_BIT;			loopSampleCount	<= VK_SAMPLE_COUNT_16_BIT;				loopSampleCount	= nextFlag(loopSampleCount))
579			{
580				const VkImageCreateFlags	actualCreateFlags	= loopCreateFlags | params.flags;
581				const VkImageUsageFlags		actualUsageFlags	= loopUsageFlags  | (params.transient ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : (VkImageUsageFlagBits)0);
582				const bool					isCube				= (actualCreateFlags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0u;
583				const VkImageCreateInfo		imageInfo			=
584				{
585					VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType          sType;
586					DE_NULL,									// const void*              pNext;
587					actualCreateFlags,							// VkImageCreateFlags       flags;
588					loopImageType,								// VkImageType              imageType;
589					loopFormat,									// VkFormat                 format;
590					makeExtentForImage(loopImageType),			// VkExtent3D               extent;
591					1u,											// uint32_t                 mipLevels;
592					(isCube ? 6u : 1u),							// uint32_t                 arrayLayers;
593					loopSampleCount,							// VkSampleCountFlagBits    samples;
594					params.tiling,								// VkImageTiling            tiling;
595					actualUsageFlags,							// VkImageUsageFlags        usage;
596					VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode            sharingMode;
597					0u,											// uint32_t                 queueFamilyIndexCount;
598					DE_NULL,									// const uint32_t*          pQueueFamilyIndices;
599					VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout            initialLayout;
600				};
601
602				if (!isImageSupported(vki, physDevice, imageInfo))
603					continue;
604
605				log << tcu::TestLog::Message << "- " << getImageInfoString(imageInfo) << tcu::TestLog::EndMessage;
606				++numCheckedImages;
607
608				const Unique<VkImage>		image			(createImage(vk, device, &imageInfo));
609				const VkMemoryRequirements	requirements	= getImageMemoryRequirements(vk, device, *image);
610				tcu::ResultCollector		result			(log, "ERROR: ");
611
612				verifyImageRequirements(result, memoryProperties, requirements, imageInfo);
613
614				// For the same tiling, transient usage, and sparse flags, (and format, if D/S) memoryTypeBits must be the same for all images
615				result.check((previousMemoryTypeBits == notInitializedBits) || (requirements.memoryTypeBits == previousMemoryTypeBits),
616								"memoryTypeBits differ from the ones in the previous image configuration");
617
618				if (result.getResult() != QP_TEST_RESULT_PASS)
619					allPass = false;
620
621				previousMemoryTypeBits = requirements.memoryTypeBits;
622			}
623		}
624	}
625
626	if (numCheckedImages == 0u)
627		log << tcu::TestLog::Message << "NOTE: No supported image configurations -- nothing to check" << tcu::TestLog::EndMessage;
628
629	return allPass ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some memory requirements were incorrect");
630}
631
632void populateTestGroup (tcu::TestCaseGroup* group)
633{
634	// Buffers
635	{
636		const struct
637		{
638			VkBufferCreateFlags		flags;
639			const char* const		name;
640		} bufferCases[] =
641		{
642			{ (VkBufferCreateFlags)0,																								"regular"					},
643			{ VK_BUFFER_CREATE_SPARSE_BINDING_BIT,																					"sparse"					},
644			{ VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,											"sparse_residency"			},
645			{ VK_BUFFER_CREATE_SPARSE_BINDING_BIT											| VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,	"sparse_aliased"			},
646			{ VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT	| VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,	"sparse_residency_aliased"	},
647		};
648
649		de::MovePtr<tcu::TestCaseGroup> bufferGroup(new tcu::TestCaseGroup(group->getTestContext(), "buffer", ""));
650
651		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bufferCases); ++ndx)
652			addFunctionCase(bufferGroup.get(), bufferCases[ndx].name, "", testBuffer, bufferCases[ndx].flags);
653
654		group->addChild(bufferGroup.release());
655	}
656
657	// Images
658	{
659		const struct
660		{
661			VkImageCreateFlags		flags;
662			bool					transient;
663			const char* const		name;
664		} imageFlagsCases[] =
665		{
666			{ (VkImageCreateFlags)0,																								false,	"regular"					},
667			{ (VkImageCreateFlags)0,																								true,	"transient"					},
668			{ VK_IMAGE_CREATE_SPARSE_BINDING_BIT,																					false,	"sparse"					},
669			{ VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT,											false,	"sparse_residency"			},
670			{ VK_IMAGE_CREATE_SPARSE_BINDING_BIT											| VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,	false,	"sparse_aliased"			},
671			{ VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT		| VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,	false,	"sparse_residency_aliased"	},
672		};
673
674		de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(group->getTestContext(), "image", ""));
675
676		for (int flagsNdx = 0; flagsNdx < DE_LENGTH_OF_ARRAY(imageFlagsCases); ++flagsNdx)
677		for (int tilingNdx = 0; tilingNdx <= 1; ++tilingNdx)
678		{
679			ImageParams			params;
680			std::ostringstream	caseName;
681
682			params.flags		=  imageFlagsCases[flagsNdx].flags;
683			params.transient	=  imageFlagsCases[flagsNdx].transient;
684			caseName			<< imageFlagsCases[flagsNdx].name;
685
686			if (tilingNdx != 0)
687			{
688				params.tiling =  VK_IMAGE_TILING_OPTIMAL;
689				caseName      << "_tiling_optimal";
690			}
691			else
692			{
693				params.tiling =  VK_IMAGE_TILING_LINEAR;
694				caseName      << "_tiling_linear";
695			}
696
697			if ((params.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) && (params.tiling == VK_IMAGE_TILING_LINEAR))
698				continue;
699
700			addFunctionCase(imageGroup.get(), caseName.str(), "", testImage, params);
701		}
702
703		group->addChild(imageGroup.release());
704	}
705}
706
707} // anonymous
708
709tcu::TestCaseGroup* createRequirementsTests (tcu::TestContext& testCtx)
710{
711	return createTestGroup(testCtx, "requirements", "Buffer and image memory requirements", populateTestGroup);
712}
713
714} // memory
715} // vkt
716