• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 namespace vkt
43 {
44 namespace memory
45 {
46 namespace
47 {
48 using namespace vk;
49 using de::MovePtr;
50 
makeBuffer(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize size,const VkBufferCreateFlags flags,const VkBufferUsageFlags usage)51 Move<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.
bitsToIndices(deUint32 bits)68 std::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 
getBufferMemoryRequirements(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize size,const VkBufferCreateFlags flags,const VkBufferUsageFlags usage)79 VkMemoryRequirements 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 
85 template<typename T>
nextEnum(T value)86 T nextEnum (T value)
87 {
88 	return static_cast<T>(static_cast<deUint32>(value) + 1);
89 }
90 
91 template<typename T>
nextFlag(T value)92 T 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 
100 template<typename T>
nextFlagExcluding(T value,T excludedFlags)101 T 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 
requireBufferSparseFeatures(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkBufferCreateFlags flags)108 void 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 
verifyBufferRequirements(tcu::ResultCollector & result,const VkPhysicalDeviceMemoryProperties & deviceMemoryProperties,const VkMemoryRequirements & requirements,const VkMemoryRequirements & allUsageFlagsRequirements,const VkPhysicalDeviceLimits & limits,const VkBufferCreateFlags bufferFlags,const VkBufferUsageFlags usage)122 void 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 
testBuffer(Context & context,const VkBufferCreateFlags bufferFlags)189 tcu::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 
requireImageSparseFeatures(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkImageCreateFlags createFlags)258 void 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 
imageUsageMatchesFormatFeatures(const VkImageUsageFlags usage,const VkFormatFeatureFlags featureFlags)272 bool 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
isImageSupported(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkImageCreateInfo & info)287 bool 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 
makeExtentForImage(const VkImageType imageType)438 VkExtent3D 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 
isFormatMatchingAspect(const VkFormat format,const VkImageAspectFlags aspect)450 bool 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 
verifyImageRequirements(tcu::ResultCollector & result,const VkPhysicalDeviceMemoryProperties & deviceMemoryProperties,const VkMemoryRequirements & requirements,const VkImageCreateInfo & imageInfo)460 void 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 
getImageInfoString(const VkImageCreateInfo & imageInfo)506 std::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 
534 struct ImageParams
535 {
536 	VkImageCreateFlags		flags;
537 	VkImageTiling			tiling;
538 	bool					transient;
539 };
540 
testImage(Context & context,const ImageParams params)541 tcu::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 
populateTestGroup(tcu::TestCaseGroup * group)632 void 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 
createRequirementsTests(tcu::TestContext & testCtx)709 tcu::TestCaseGroup* createRequirementsTests (tcu::TestContext& testCtx)
710 {
711 	return createTestGroup(testCtx, "requirements", "Buffer and image memory requirements", populateTestGroup);
712 }
713 
714 } // memory
715 } // vkt
716