• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google 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 Simple memory mapping tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktMemoryMappingTests.hpp"
25 
26 #include "vktTestCaseUtil.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 
29 #include "tcuMaybe.hpp"
30 #include "tcuResultCollector.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuPlatform.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuCommandLine.hpp"
35 
36 #include "vkDeviceUtil.hpp"
37 #include "vkPlatform.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkRef.hpp"
40 #include "vkRefUtil.hpp"
41 #include "vkStrUtil.hpp"
42 #include "vkAllocationCallbackUtil.hpp"
43 #include "vkImageUtil.hpp"
44 
45 #include "deRandom.hpp"
46 #include "deSharedPtr.hpp"
47 #include "deStringUtil.hpp"
48 #include "deUniquePtr.hpp"
49 #include "deSTLUtil.hpp"
50 #include "deMath.h"
51 
52 #include <string>
53 #include <vector>
54 #include <algorithm>
55 
56 using tcu::Maybe;
57 using tcu::TestLog;
58 
59 using de::SharedPtr;
60 
61 using std::string;
62 using std::vector;
63 using std::pair;
64 
65 using namespace vk;
66 
67 namespace vkt
68 {
69 namespace memory
70 {
71 namespace
72 {
73 template<typename T>
divRoundUp(const T & a,const T & b)74 T divRoundUp (const T& a, const T& b)
75 {
76 	return (a / b) + (a % b == 0 ? 0 : 1);
77 }
78 
79 template<typename T>
roundDownToMultiple(const T & a,const T & b)80 T roundDownToMultiple (const T& a, const T& b)
81 {
82 	return b * (a / b);
83 }
84 
85 template<typename T>
roundUpToMultiple(const T & a,const T & b)86 T roundUpToMultiple (const T& a, const T& b)
87 {
88 	return b * (a / b + (a % b != 0 ? 1 : 0));
89 }
90 
91 enum AllocationKind
92 {
93 	ALLOCATION_KIND_SUBALLOCATED										= 0,
94 	ALLOCATION_KIND_DEDICATED_BUFFER									= 1,
95 	ALLOCATION_KIND_DEDICATED_IMAGE										= 2,
96 	ALLOCATION_KIND_LAST
97 };
98 
mapMemoryWrapper(const DeviceInterface & vkd,VkDevice device,vk::VkDeviceMemory memory,VkDeviceSize mappingOffset,VkDeviceSize mappingSize,void ** ptr,bool useMap2)99 void mapMemoryWrapper(const DeviceInterface& vkd, VkDevice device, vk::VkDeviceMemory memory, VkDeviceSize mappingOffset, VkDeviceSize mappingSize, void** ptr, bool useMap2)
100 {
101 	if (!useMap2)
102 	{
103 		VK_CHECK(vkd.mapMemory(device, memory, mappingOffset, mappingSize, 0u, ptr));
104 	}
105 	else
106 	{
107 		const VkMemoryMapInfoKHR info =
108 		{
109 			VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR,	// VkStructureType	sType
110 			nullptr,								// const void		*pNext
111 			0u,										// VkMemoryMapFlags flags
112 			memory,									// VkDeviceMemory	memory
113 			mappingOffset,							// VkDeviceSize		offset
114 			mappingSize,							// VkDeviceSize		size
115 		};
116 		VK_CHECK(vkd.mapMemory2KHR(device, &info, ptr));
117 	}
118 }
119 
unmapMemoryWrapper(const DeviceInterface & vkd,VkDevice device,vk::VkDeviceMemory memory,bool useMap2)120 void unmapMemoryWrapper(const DeviceInterface& vkd, VkDevice device, vk::VkDeviceMemory memory, bool useMap2)
121 {
122 	if (!useMap2)
123 	{
124 		vkd.unmapMemory(device, memory);
125 	}
126 	else
127 	{
128 		const VkMemoryUnmapInfoKHR unmap {
129 			VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR,	// VkStructureType			sType
130 			nullptr,									// const void*				pNext
131 			0u,											// VkMemoryUnmapFlagsEXT	flags
132 			memory,										// VkDeviceMemory			memory
133 		};
134 		VK_CHECK(vkd.unmapMemory2KHR(device, &unmap));
135 	}
136 }
137 
138 // \note Bit vector that guarantees that each value takes only one bit.
139 // std::vector<bool> is often optimized to only take one bit for each bool, but
140 // that is implementation detail and in this case we really need to known how much
141 // memory is used.
142 class BitVector
143 {
144 public:
145 	enum
146 	{
147 		BLOCK_BIT_SIZE = 8 * sizeof(deUint32)
148 	};
149 
BitVector(size_t size,bool value=false)150 	BitVector (size_t size, bool value = false)
151 		: m_data(divRoundUp<size_t>(size, (size_t)BLOCK_BIT_SIZE), value ? ~0x0u : 0x0u)
152 	{
153 	}
154 
get(size_t ndx) const155 	bool get (size_t ndx) const
156 	{
157 		return (m_data[ndx / BLOCK_BIT_SIZE] & (0x1u << (deUint32)(ndx % BLOCK_BIT_SIZE))) != 0;
158 	}
159 
set(size_t ndx,bool value)160 	void set (size_t ndx, bool value)
161 	{
162 		if (value)
163 			m_data[ndx / BLOCK_BIT_SIZE] |= 0x1u << (deUint32)(ndx % BLOCK_BIT_SIZE);
164 		else
165 			m_data[ndx / BLOCK_BIT_SIZE] &= ~(0x1u << (deUint32)(ndx % BLOCK_BIT_SIZE));
166 	}
167 
setRange(size_t offset,size_t count,bool value)168 	void setRange (size_t offset, size_t count, bool value)
169 	{
170 		size_t ndx = offset;
171 
172 		for (; (ndx < offset + count) && ((ndx % BLOCK_BIT_SIZE) != 0); ndx++)
173 		{
174 			DE_ASSERT(ndx >= offset);
175 			DE_ASSERT(ndx < offset + count);
176 			set(ndx, value);
177 		}
178 
179 		{
180 			const size_t endOfFullBlockNdx = roundDownToMultiple<size_t>(offset + count, BLOCK_BIT_SIZE);
181 
182 			if (ndx < endOfFullBlockNdx)
183 			{
184 				deMemset(&m_data[ndx / BLOCK_BIT_SIZE], (value ? 0xFF : 0x0), (endOfFullBlockNdx - ndx) / 8);
185 				ndx = endOfFullBlockNdx;
186 			}
187 		}
188 
189 		for (; ndx < offset + count; ndx++)
190 		{
191 			DE_ASSERT(ndx >= offset);
192 			DE_ASSERT(ndx < offset + count);
193 			set(ndx, value);
194 		}
195 	}
196 
vectorAnd(const BitVector & other,size_t offset,size_t count)197 	void vectorAnd (const BitVector& other, size_t offset, size_t count)
198 	{
199 		size_t ndx = offset;
200 
201 		for (; ndx < offset + count && (ndx % BLOCK_BIT_SIZE) != 0; ndx++)
202 		{
203 			DE_ASSERT(ndx >= offset);
204 			DE_ASSERT(ndx < offset + count);
205 			set(ndx, other.get(ndx) && get(ndx));
206 		}
207 
208 		for (; ndx < roundDownToMultiple<size_t>(offset + count, BLOCK_BIT_SIZE); ndx += BLOCK_BIT_SIZE)
209 		{
210 			DE_ASSERT(ndx >= offset);
211 			DE_ASSERT(ndx < offset + count);
212 			DE_ASSERT(ndx % BLOCK_BIT_SIZE == 0);
213 			DE_ASSERT(ndx + BLOCK_BIT_SIZE <= offset + count);
214 			m_data[ndx / BLOCK_BIT_SIZE] &= other.m_data[ndx / BLOCK_BIT_SIZE];
215 		}
216 
217 		for (; ndx < offset + count; ndx++)
218 		{
219 			DE_ASSERT(ndx >= offset);
220 			DE_ASSERT(ndx < offset + count);
221 			set(ndx, other.get(ndx) && get(ndx));
222 		}
223 	}
224 
225 private:
226 	vector<deUint32>	m_data;
227 };
228 
229 class ReferenceMemory
230 {
231 public:
ReferenceMemory(size_t size,size_t atomSize)232 	ReferenceMemory (size_t size, size_t atomSize)
233 		: m_atomSize	(atomSize)
234 		, m_bytes		(size, 0xDEu)
235 		, m_defined		(size, false)
236 		, m_flushed		(size / atomSize, false)
237 	{
238 		DE_ASSERT(size % m_atomSize == 0);
239 	}
240 
write(size_t pos,deUint8 value)241 	void write (size_t pos, deUint8 value)
242 	{
243 		m_bytes[pos] = value;
244 		m_defined.set(pos, true);
245 		m_flushed.set(pos / m_atomSize, false);
246 	}
247 
read(size_t pos,deUint8 value)248 	bool read (size_t pos, deUint8 value)
249 	{
250 		const bool isOk = !m_defined.get(pos)
251 						|| m_bytes[pos] == value;
252 
253 		m_bytes[pos] = value;
254 		m_defined.set(pos, true);
255 
256 		return isOk;
257 	}
258 
modifyXor(size_t pos,deUint8 value,deUint8 mask)259 	bool modifyXor (size_t pos, deUint8 value, deUint8 mask)
260 	{
261 		const bool isOk = !m_defined.get(pos)
262 						|| m_bytes[pos] == value;
263 
264 		m_bytes[pos] = value ^ mask;
265 		m_defined.set(pos, true);
266 		m_flushed.set(pos / m_atomSize, false);
267 
268 		return isOk;
269 	}
270 
flush(size_t offset,size_t size)271 	void flush (size_t offset, size_t size)
272 	{
273 		DE_ASSERT((offset % m_atomSize) == 0);
274 		DE_ASSERT((size % m_atomSize) == 0);
275 
276 		m_flushed.setRange(offset / m_atomSize, size / m_atomSize, true);
277 	}
278 
invalidate(size_t offset,size_t size)279 	void invalidate (size_t offset, size_t size)
280 	{
281 		DE_ASSERT((offset % m_atomSize) == 0);
282 		DE_ASSERT((size % m_atomSize) == 0);
283 
284 		if (m_atomSize == 1)
285 		{
286 			m_defined.vectorAnd(m_flushed, offset, size);
287 		}
288 		else
289 		{
290 			for (size_t ndx = 0; ndx < size / m_atomSize; ndx++)
291 			{
292 				if (!m_flushed.get((offset / m_atomSize) + ndx))
293 					m_defined.setRange(offset + ndx * m_atomSize, m_atomSize, false);
294 			}
295 		}
296 	}
297 
298 
299 private:
300 	const size_t	m_atomSize;
301 	vector<deUint8>	m_bytes;
302 	BitVector		m_defined;
303 	BitVector		m_flushed;
304 };
305 
306 struct MemoryType
307 {
MemoryTypevkt::memory::__anonb6ec36930111::MemoryType308 	MemoryType		(deUint32 index_, const VkMemoryType& type_)
309 		: index	(index_)
310 		, type	(type_)
311 	{
312 	}
313 
MemoryTypevkt::memory::__anonb6ec36930111::MemoryType314 	MemoryType		(void)
315 		: index	(~0u)
316 	{
317 	}
318 
319 	deUint32		index;
320 	VkMemoryType	type;
321 };
322 
computeDeviceMemorySystemMemFootprint(const DeviceInterface & vk,VkDevice device)323 size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device)
324 {
325 	AllocationCallbackRecorder	callbackRecorder	(getSystemAllocator());
326 
327 	{
328 		// 1 B allocation from memory type 0
329 		const VkMemoryAllocateInfo	allocInfo	=
330 		{
331 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
332 			DE_NULL,
333 			1u,
334 			0u,
335 		};
336 		const Unique<VkDeviceMemory>			memory			(allocateMemory(vk, device, &allocInfo, callbackRecorder.getCallbacks()));
337 		AllocationCallbackValidationResults		validateRes;
338 
339 		validateAllocationCallbacks(callbackRecorder, &validateRes);
340 
341 		TCU_CHECK(validateRes.violations.empty());
342 
343 		return getLiveSystemAllocationTotal(validateRes)
344 			   + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead
345 	}
346 }
347 
makeImage(const DeviceInterface & vk,VkDevice device,VkDeviceSize size,deUint32 queueFamilyIndex)348 Move<VkImage> makeImage (const DeviceInterface& vk, VkDevice device, VkDeviceSize size, deUint32 queueFamilyIndex)
349 {
350 	const VkFormat formats[] =
351 	{
352 		VK_FORMAT_R8G8B8A8_UINT,
353 		VK_FORMAT_R16G16B16A16_UINT,
354 		VK_FORMAT_R32G32B32A32_UINT,
355 	};
356 
357 	VkFormat	format			= VK_FORMAT_UNDEFINED;
358 	deUint32	powerOfTwoSize	= 0;
359 
360 	for (const VkFormat f : formats)
361 	{
362 		const int			pixelSize		= vk::mapVkFormat(f).getPixelSize();
363 		const VkDeviceSize	sizeInPixels	= (size + 3u) / pixelSize;
364 		const deUint32		sqrtSize		= static_cast<deUint32>(deFloatCeil(deFloatSqrt(static_cast<float>(sizeInPixels))));
365 
366 		format			= f;
367 		powerOfTwoSize	= deSmallestGreaterOrEquallPowerOfTwoU32(sqrtSize);
368 
369 		// maxImageDimension2D
370 		if (powerOfTwoSize < 4096)
371 			break;
372 	}
373 
374 	const VkImageCreateInfo				colorImageParams				=
375 	{
376 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType;
377 		DE_NULL,														// const void*				pNext;
378 		0u,																// VkImageCreateFlags		flags;
379 		VK_IMAGE_TYPE_2D,												// VkImageType				imageType;
380 		format,															// VkFormat					format;
381 		{
382 			powerOfTwoSize,
383 			powerOfTwoSize,
384 			1u
385 		},																// VkExtent3D				extent;
386 		1u,																// deUint32					mipLevels;
387 		1u,																// deUint32					arraySize;
388 		VK_SAMPLE_COUNT_1_BIT,											// deUint32					samples;
389 		VK_IMAGE_TILING_LINEAR,											// VkImageTiling			tiling;
390 		VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags		usage;
391 		VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode;
392 		1u,																// deUint32					queueFamilyCount;
393 		&queueFamilyIndex,												// const deUint32*			pQueueFamilyIndices;
394 		VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout			initialLayout;
395 	};
396 
397 	return createImage(vk, device, &colorImageParams);
398 }
399 
makeBuffer(const DeviceInterface & vk,VkDevice device,VkDeviceSize size,deUint32 queueFamilyIndex)400 Move<VkBuffer> makeBuffer(const DeviceInterface& vk, VkDevice device, VkDeviceSize size, deUint32 queueFamilyIndex)
401 {
402 	const VkBufferCreateInfo			bufferParams					=
403 	{
404 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							//	VkStructureType			sType;
405 		DE_NULL,														//	const void*				pNext;
406 		0u,																//	VkBufferCreateFlags		flags;
407 		size,															//	VkDeviceSize			size;
408 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, //	VkBufferUsageFlags	usage;
409 		VK_SHARING_MODE_EXCLUSIVE,										//	VkSharingMode			sharingMode;
410 		1u,																//	deUint32				queueFamilyCount;
411 		&queueFamilyIndex,												//	const deUint32*			pQueueFamilyIndices;
412 	};
413 	return vk::createBuffer(vk, device, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
414 }
415 
getImageMemoryRequirements(const DeviceInterface & vk,VkDevice device,Move<VkImage> & image)416 VkMemoryRequirements getImageMemoryRequirements(const DeviceInterface& vk, VkDevice device, Move<VkImage>& image)
417 {
418 	VkImageMemoryRequirementsInfo2	info								=
419 	{
420 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,				// VkStructureType			sType
421 		DE_NULL,														// const void*				pNext
422 		*image															// VkImage					image
423 	};
424 	VkMemoryDedicatedRequirements	dedicatedRequirements				=
425 	{
426 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType			sType
427 		DE_NULL,														// const void*				pNext
428 		VK_FALSE,														// VkBool32					prefersDedicatedAllocation
429 		VK_FALSE														// VkBool32					requiresDedicatedAllocation
430 	};
431 	VkMemoryRequirements2			req2								=
432 	{
433 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType			sType
434 		&dedicatedRequirements,											// void*					pNext
435 		{0, 0, 0}														// VkMemoryRequirements		memoryRequirements
436 	};
437 
438 	vk.getImageMemoryRequirements2(device, &info, &req2);
439 
440 	return req2.memoryRequirements;
441 }
442 
getBufferMemoryRequirements(const DeviceInterface & vk,VkDevice device,Move<VkBuffer> & buffer)443 VkMemoryRequirements getBufferMemoryRequirements(const DeviceInterface& vk, VkDevice device, Move<VkBuffer>& buffer)
444 {
445 	VkBufferMemoryRequirementsInfo2	info								=
446 	{
447 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,			// VkStructureType			sType
448 		DE_NULL,														// const void*				pNext
449 		*buffer															// VkImage					image
450 	};
451 	VkMemoryDedicatedRequirements	dedicatedRequirements				=
452 	{
453 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType			sType
454 		DE_NULL,														// const void*				pNext
455 		VK_FALSE,														// VkBool32					prefersDedicatedAllocation
456 		VK_FALSE														// VkBool32					requiresDedicatedAllocation
457 	};
458 	VkMemoryRequirements2			req2								=
459 	{
460 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType		sType
461 		&dedicatedRequirements,											// void*				pNext
462 		{0, 0, 0}														// VkMemoryRequirements	memoryRequirements
463 	};
464 
465 	vk.getBufferMemoryRequirements2(device, &info, &req2);
466 
467 	return req2.memoryRequirements;
468 }
469 
allocMemory(const DeviceInterface & vk,VkDevice device,VkDeviceSize pAllocInfo_allocationSize,deUint32 pAllocInfo_memoryTypeIndex)470 Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, VkDeviceSize pAllocInfo_allocationSize, deUint32 pAllocInfo_memoryTypeIndex)
471 {
472 	const VkMemoryAllocateInfo			pAllocInfo						=
473 	{
474 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
475 		DE_NULL,
476 		pAllocInfo_allocationSize,
477 		pAllocInfo_memoryTypeIndex,
478 	};
479 	return allocateMemory(vk, device, &pAllocInfo);
480 }
481 
findLargeAllocationSize(const DeviceInterface & vk,VkDevice device,VkDeviceSize max,deUint32 memoryTypeIndex)482 VkDeviceSize findLargeAllocationSize (const DeviceInterface& vk, VkDevice device, VkDeviceSize max, deUint32 memoryTypeIndex)
483 {
484 	// max must be power of two
485 	DE_ASSERT((max & (max - 1)) == 0);
486 
487 	for (VkDeviceSize size = max; size > 0; size >>= 1)
488 	{
489 		const VkMemoryAllocateInfo	allocInfo	=
490 		{
491 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
492 			DE_NULL,
493 			size,
494 			memoryTypeIndex,
495 		};
496 
497 		VkDeviceMemory				memory;
498 		VkResult					result		= vk.allocateMemory(device, &allocInfo, NULL, &memory);
499 
500 		if (result == VK_SUCCESS)
501 		{
502 			vk.freeMemory(device, memory, NULL);
503 			return size;
504 		}
505 	}
506 
507 	return 0;
508 }
509 
allocMemory(const DeviceInterface & vk,VkDevice device,VkDeviceSize pAllocInfo_allocationSize,deUint32 pAllocInfo_memoryTypeIndex,Move<VkImage> & image,Move<VkBuffer> & buffer,const VkAllocationCallbacks * allocator=DE_NULL)510 Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, VkDeviceSize pAllocInfo_allocationSize, deUint32 pAllocInfo_memoryTypeIndex, Move<VkImage>& image, Move<VkBuffer>& buffer, const VkAllocationCallbacks* allocator = DE_NULL)
511 {
512 	DE_ASSERT((!image) || (!buffer));
513 
514 	const VkMemoryDedicatedAllocateInfo
515 										dedicatedAllocateInfo			=
516 	{
517 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,				// VkStructureType		sType
518 		DE_NULL,														// const void*			pNext
519 		*image,															// VkImage				image
520 		*buffer															// VkBuffer				buffer
521 	};
522 
523 	const VkMemoryAllocateInfo			pAllocInfo						=
524 	{
525 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
526 		!image && !buffer ? DE_NULL : &dedicatedAllocateInfo,
527 		pAllocInfo_allocationSize,
528 		pAllocInfo_memoryTypeIndex,
529 	};
530 	return allocateMemory(vk, device, &pAllocInfo, allocator);
531 }
532 
533 struct MemoryRange
534 {
MemoryRangevkt::memory::__anonb6ec36930111::MemoryRange535 	MemoryRange (VkDeviceSize offset_ = ~(VkDeviceSize)0, VkDeviceSize size_ = ~(VkDeviceSize)0)
536 		: offset	(offset_)
537 		, size		(size_)
538 	{
539 	}
540 
541 	VkDeviceSize	offset;
542 	VkDeviceSize	size;
543 };
544 
545 struct TestConfig
546 {
TestConfigvkt::memory::__anonb6ec36930111::TestConfig547 	TestConfig (void)
548 		: allocationSize	(~(VkDeviceSize)0)
549 		, allocationKind	(ALLOCATION_KIND_SUBALLOCATED)
550 	{
551 	}
552 
553 	VkDeviceSize		allocationSize;
554 	deUint32			seed;
555 
556 	MemoryRange			mapping;
557 	vector<MemoryRange>	flushMappings;
558 	vector<MemoryRange>	invalidateMappings;
559 	bool				remap;
560 	bool				implicitUnmap;
561 	AllocationKind		allocationKind;
562 	bool				memoryMap2;
563 };
564 
compareAndLogBuffer(TestLog & log,size_t size,size_t referenceSize,const deUint8 * result,const deUint8 * reference)565 bool compareAndLogBuffer (TestLog& log, size_t size, size_t referenceSize, const deUint8* result, const deUint8* reference)
566 {
567 	size_t	stride		= size / referenceSize;
568 	size_t	failedBytes	= 0;
569 	size_t	firstFailed	= (size_t)-1;
570 
571 	DE_ASSERT(referenceSize <= size);
572 
573 	for (size_t ndx = 0; ndx < referenceSize; ndx += stride)
574 	{
575 		if (result[ndx * stride] != reference[ndx])
576 		{
577 			failedBytes++;
578 
579 			if (firstFailed == (size_t)-1)
580 				firstFailed = ndx;
581 		}
582 	}
583 
584 	if (failedBytes > 0)
585 	{
586 		log << TestLog::Message << "Comparison failed. Failed bytes " << failedBytes << ". First failed at offset " << firstFailed << "." << TestLog::EndMessage;
587 
588 		std::ostringstream	expectedValues;
589 		std::ostringstream	resultValues;
590 
591 		for (size_t ndx = firstFailed; ndx < firstFailed + 10 && ndx < referenceSize; ndx++)
592 		{
593 			if (ndx != firstFailed)
594 			{
595 				expectedValues << ", ";
596 				resultValues << ", ";
597 			}
598 
599 			expectedValues << reference[ndx];
600 			resultValues << result[ndx * stride];
601 		}
602 
603 		if (firstFailed + 10 < size)
604 		{
605 			expectedValues << "...";
606 			resultValues << "...";
607 		}
608 
609 		log << TestLog::Message << "Expected values at offset: " << firstFailed << ", " << expectedValues.str() << TestLog::EndMessage;
610 		log << TestLog::Message << "Result values at offset: " << firstFailed << ", " << resultValues.str() << TestLog::EndMessage;
611 
612 		return false;
613 	}
614 	else
615 		return true;
616 }
617 
createProtectedMemoryDevice(const Context & context,const VkPhysicalDeviceFeatures2 & features2)618 static Move<VkDevice> createProtectedMemoryDevice(const Context& context, const VkPhysicalDeviceFeatures2& features2)
619 {
620 	auto&											cmdLine					= context.getTestContext().getCommandLine();
621 	const InstanceInterface&						vki						= context.getInstanceInterface();
622 	const float										queuePriority			= 1.0f;
623 	deUint32										queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
624 
625 	// Enable VK_KHR_map_memory2 if supported, as required by some tests.
626 	std::vector<const char*> enabledExtensions;
627 	if (context.isDeviceFunctionalitySupported("VK_KHR_map_memory2"))
628 		enabledExtensions.push_back("VK_KHR_map_memory2");
629 
630 	VkDeviceQueueCreateInfo							queueInfo		=
631 	{
632 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,					// VkStructureType					sType;
633 		DE_NULL,													// const void*						pNext;
634 		vk::VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT,					// VkDeviceQueueCreateFlags			flags;
635 		queueFamilyIndex,											// deUint32							queueFamilyIndex;
636 		1u,															// deUint32							queueCount;
637 		&queuePriority												// const float*						pQueuePriorities;
638 	};
639 
640 	const VkDeviceCreateInfo						deviceInfo		=
641 	{
642 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,						// VkStructureType					sType;
643 		&features2,													// const void*						pNext;
644 		(VkDeviceCreateFlags)0,										// VkDeviceCreateFlags				flags;
645 		1u,															// uint32_t							queueCreateInfoCount;
646 		&queueInfo,													// const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
647 		0u,															// uint32_t							enabledLayerCount;
648 		nullptr,													// const char* const*				ppEnabledLayerNames;
649 		de::sizeU32(enabledExtensions),								// uint32_t							enabledExtensionCount;
650 		de::dataOrNull(enabledExtensions),							// const char* const*				ppEnabledExtensionNames;
651 		nullptr,													// const VkPhysicalDeviceFeatures*	pEnabledFeatures;
652 	};
653 
654 	return createCustomDevice(cmdLine.isValidationEnabled(), context.getPlatformInterface(), context.getInstance(), vki, context.getPhysicalDevice(), &deviceInfo);
655 }
656 
testMemoryMapping(Context & context,const TestConfig config)657 tcu::TestStatus testMemoryMapping (Context& context, const TestConfig config)
658 {
659 	TestLog&								log							= context.getTestContext().getLog();
660 	tcu::ResultCollector					result						(log);
661 	bool									atLeastOneTestPerformed		= false;
662 	const VkPhysicalDevice					physicalDevice				= context.getPhysicalDevice();
663 	const InstanceInterface&				vki							= context.getInstanceInterface();
664 	const DeviceInterface&					vkd							= context.getDeviceInterface();
665 	const VkPhysicalDeviceMemoryProperties	memoryProperties			= getPhysicalDeviceMemoryProperties(vki, physicalDevice);
666 	const VkDeviceSize						nonCoherentAtomSize			= context.getDeviceProperties().limits.nonCoherentAtomSize;
667 	const deUint32							queueFamilyIndex			= context.getUniversalQueueFamilyIndex();
668 
669 	//Create protected memory device if protected memory is supported
670 	//otherwise use the default device
671 	Move<VkDevice>	protectMemoryDevice;
672 	VkDevice		device;
673 	{
674 		VkPhysicalDeviceProtectedMemoryFeatures		protectedFeatures;
675 		protectedFeatures.sType				= vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
676 		protectedFeatures.pNext				= DE_NULL;
677 		protectedFeatures.protectedMemory	= VK_FALSE;
678 
679 		VkPhysicalDeviceFeatures2					deviceFeatures2;
680 		deviceFeatures2.sType		= vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
681 		deviceFeatures2.pNext		= &protectedFeatures;
682 
683 		vki.getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &deviceFeatures2);
684 		if(protectedFeatures.protectedMemory && config.implicitUnmap)
685 		{
686 			protectMemoryDevice = createProtectedMemoryDevice(context, deviceFeatures2);
687 			device = *protectMemoryDevice;
688 		}
689 		else
690 		{
691 			device = context.getDevice();
692 		}
693 	}
694 
695 	{
696 		const tcu::ScopedLogSection	section	(log, "TestCaseInfo", "TestCaseInfo");
697 
698 		log << TestLog::Message << "Seed: " << config.seed << TestLog::EndMessage;
699 		log << TestLog::Message << "Allocation size: " << config.allocationSize  <<  TestLog::EndMessage;
700 		log << TestLog::Message << "Mapping, offset: " << config.mapping.offset << ", size: " << config.mapping.size << TestLog::EndMessage;
701 
702 		if (!config.flushMappings.empty())
703 		{
704 			log << TestLog::Message << "Invalidating following ranges:" << TestLog::EndMessage;
705 
706 			for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
707 				log << TestLog::Message << "\tOffset: " << config.flushMappings[ndx].offset << ", Size: " << config.flushMappings[ndx].size << TestLog::EndMessage;
708 		}
709 
710 		if (config.remap)
711 			log << TestLog::Message << "Remapping memory between flush and invalidation." << TestLog::EndMessage;
712 
713 		if (!config.invalidateMappings.empty())
714 		{
715 			log << TestLog::Message << "Flushing following ranges:" << TestLog::EndMessage;
716 
717 			for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
718 				log << TestLog::Message << "\tOffset: " << config.invalidateMappings[ndx].offset << ", Size: " << config.invalidateMappings[ndx].size << TestLog::EndMessage;
719 		}
720 	}
721 
722 	for (deUint32 memoryTypeIndex = 0; memoryTypeIndex < memoryProperties.memoryTypeCount; memoryTypeIndex++)
723 	{
724 		try
725 		{
726 			const tcu::ScopedLogSection		section			(log, "MemoryType" + de::toString(memoryTypeIndex), "MemoryType" + de::toString(memoryTypeIndex));
727 			const vk::VkMemoryType&			memoryType		= memoryProperties.memoryTypes[memoryTypeIndex];
728 			const VkMemoryHeap&				memoryHeap		= memoryProperties.memoryHeaps[memoryType.heapIndex];
729 			const VkDeviceSize				atomSize		= nonCoherentAtomSize;
730 			const VkDeviceSize				stride			= config.implicitUnmap ? 1024 : 1;
731 			const deUint32					iterations		= config.implicitUnmap ? 128 : 1;
732 
733 			VkDeviceSize					allocationSize	= (config.allocationSize % atomSize == 0) ? config.allocationSize : config.allocationSize + (atomSize - (config.allocationSize % atomSize));
734 			size_t							referenceSize	= 0;
735 			vector<deUint8>					reference;
736 
737 			if ((memoryType.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD) != 0 && !context.getCoherentMemoryFeaturesAMD().deviceCoherentMemory)
738 				continue;
739 
740 			if (config.implicitUnmap)
741 			{
742 				VkDeviceSize max	= 0x10000000; // 256MiB
743 
744 				while (memoryHeap.size <= 4 * max)
745 					max >>= 1;
746 
747 				allocationSize		= findLargeAllocationSize(vkd, device, max, memoryTypeIndex);
748 			}
749 
750 			vk::VkMemoryRequirements		req				=
751 			{
752 				(VkDeviceSize)allocationSize,
753 				(VkDeviceSize)0,
754 				~(deUint32)0u
755 			};
756 			Move<VkImage>					image;
757 			Move<VkBuffer>					buffer;
758 
759 			if (config.allocationKind == ALLOCATION_KIND_DEDICATED_IMAGE)
760 			{
761 				image = makeImage(vkd, device, allocationSize, queueFamilyIndex);
762 				req = getImageMemoryRequirements(vkd, device, image);
763 			}
764 			else if (config.allocationKind == ALLOCATION_KIND_DEDICATED_BUFFER)
765 			{
766 				buffer = makeBuffer(vkd, device, allocationSize, queueFamilyIndex);
767 				req = getBufferMemoryRequirements(vkd, device, buffer);
768 			}
769 			allocationSize = req.size;
770 			VkDeviceSize					mappingSize					=  (config.mapping.size % atomSize == 0) ? config.mapping.size : config.mapping.size + (atomSize - (config.mapping.size % atomSize));
771 			VkDeviceSize					mappingOffset				=  (config.mapping.offset % atomSize == 0) ? config.mapping.offset : config.mapping.offset - (config.mapping.offset % atomSize);
772 			if (config.mapping.size == config.allocationSize && config.mapping.offset == 0u)
773 			{
774 				mappingSize = allocationSize;
775 			}
776 
777 			referenceSize = static_cast<size_t>(mappingSize / stride);
778 			reference.resize(static_cast<size_t>(mappingOffset) + referenceSize);
779 
780 			log << TestLog::Message << "MemoryType: " << memoryType << TestLog::EndMessage;
781 			log << TestLog::Message << "MemoryHeap: " << memoryHeap << TestLog::EndMessage;
782 			log << TestLog::Message << "AtomSize: " << atomSize << TestLog::EndMessage;
783 			log << TestLog::Message << "AllocationSize: " << allocationSize << TestLog::EndMessage;
784 			log << TestLog::Message << "Mapping, offset: " << mappingOffset << ", size: " << mappingSize << TestLog::EndMessage;
785 
786 			if ((req.memoryTypeBits & (1u << memoryTypeIndex)) == 0)
787 			{
788 				static const char* const allocationKindName[] =
789 				{
790 					"suballocation",
791 					"dedicated allocation of buffers",
792 					"dedicated allocation of images"
793 				};
794 				log << TestLog::Message << "Memory type does not support " << allocationKindName[static_cast<deUint32>(config.allocationKind)] << '.' << TestLog::EndMessage;
795 				continue;
796 			}
797 
798 			if (!config.flushMappings.empty())
799 			{
800 				log << TestLog::Message << "Invalidating following ranges:" << TestLog::EndMessage;
801 
802 				for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
803 				{
804 					const VkDeviceSize	offset	= (config.flushMappings[ndx].offset % atomSize == 0) ? config.flushMappings[ndx].offset : config.flushMappings[ndx].offset - (config.flushMappings[ndx].offset % atomSize);
805 					const VkDeviceSize	size	= (config.flushMappings[ndx].size % atomSize == 0) ? config.flushMappings[ndx].size : config.flushMappings[ndx].size + (atomSize - (config.flushMappings[ndx].size % atomSize));
806 					log << TestLog::Message << "\tOffset: " << offset << ", Size: " << size << TestLog::EndMessage;
807 				}
808 			}
809 
810 			if (!config.invalidateMappings.empty())
811 			{
812 				log << TestLog::Message << "Flushing following ranges:" << TestLog::EndMessage;
813 
814 				for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
815 				{
816 					const VkDeviceSize	offset = (config.invalidateMappings[ndx].offset % atomSize == 0) ? config.invalidateMappings[ndx].offset : config.invalidateMappings[ndx].offset - (config.invalidateMappings[ndx].offset % atomSize);
817 					const VkDeviceSize	size = (config.invalidateMappings[ndx].size % atomSize == 0) ? config.invalidateMappings[ndx].size : config.invalidateMappings[ndx].size + (atomSize - (config.invalidateMappings[ndx].size % atomSize));
818 					log << TestLog::Message << "\tOffset: " << offset << ", Size: " << size << TestLog::EndMessage;
819 				}
820 			}
821 
822 			if ((memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
823 			{
824 				log << TestLog::Message << "Memory type doesn't support mapping." << TestLog::EndMessage;
825 			}
826 			else if (memoryHeap.size <= 4 * allocationSize)
827 			{
828 				log << TestLog::Message << "Memory type's heap is too small." << TestLog::EndMessage;
829 			}
830 			else for (deUint32 iteration = 0; iteration < iterations; iteration++)
831 			{
832 				atLeastOneTestPerformed = true;
833 				AllocationCallbackRecorder		recorder			(getSystemAllocator());
834 				const VkAllocationCallbacks*	allocator			= config.implicitUnmap ? recorder.getCallbacks() : DE_NULL;
835 				Move<VkDeviceMemory>			memory				(allocMemory(vkd, device, allocationSize, memoryTypeIndex, image, buffer, allocator));
836 				de::Random						rng					(config.seed);
837 				deUint8*						mapping				= DE_NULL;
838 
839 				{
840 					void* ptr;
841 					mapMemoryWrapper(vkd, device, *memory, mappingOffset, mappingSize, &ptr, config.memoryMap2);
842 					TCU_CHECK(ptr);
843 
844 					mapping = (deUint8*)ptr;
845 				}
846 
847 				for (VkDeviceSize ndx = 0; ndx < referenceSize; ndx += stride)
848 				{
849 					const deUint8 val = rng.getUint8();
850 
851 					mapping[ndx * stride]						= val;
852 					reference[(size_t)(mappingOffset + ndx)]	= val;
853 				}
854 
855 				if (!config.flushMappings.empty())
856 				{
857 					vector<VkMappedMemoryRange> ranges;
858 
859 					for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
860 					{
861 						const VkMappedMemoryRange range =
862 						{
863 							VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
864 							DE_NULL,
865 
866 							*memory,
867 							(config.flushMappings[ndx].offset % atomSize == 0) ? config.flushMappings[ndx].offset : config.flushMappings[ndx].offset - (config.flushMappings[ndx].offset % atomSize),
868 							(config.flushMappings[ndx].size % atomSize == 0) ? config.flushMappings[ndx].size : config.flushMappings[ndx].size + (atomSize - (config.flushMappings[ndx].size % atomSize)),
869 						};
870 
871 						ranges.push_back(range);
872 					}
873 
874 					VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), &ranges[0]));
875 				}
876 
877 				if (config.remap)
878 				{
879 					unmapMemoryWrapper(vkd, device, *memory, config.memoryMap2);
880 					void* ptr;
881 					mapMemoryWrapper(vkd, device, *memory, mappingOffset, mappingSize, &ptr, config.memoryMap2);
882 
883 					TCU_CHECK(ptr);
884 
885 					mapping = (deUint8*)ptr;
886 				}
887 
888 				if (!config.invalidateMappings.empty())
889 				{
890 					vector<VkMappedMemoryRange> ranges;
891 
892 					for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
893 					{
894 						const VkMappedMemoryRange range =
895 						{
896 							VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
897 							DE_NULL,
898 
899 							*memory,
900 							(config.invalidateMappings[ndx].offset % atomSize == 0) ? config.invalidateMappings[ndx].offset : config.invalidateMappings[ndx].offset - (config.invalidateMappings[ndx].offset % atomSize),
901 							(config.invalidateMappings[ndx].size % atomSize == 0) ? config.invalidateMappings[ndx].size : config.invalidateMappings[ndx].size + (atomSize - (config.invalidateMappings[ndx].size % atomSize)),
902 						};
903 
904 						ranges.push_back(range);
905 					}
906 
907 					VK_CHECK(vkd.invalidateMappedMemoryRanges(device, static_cast<deUint32>(ranges.size()), &ranges[0]));
908 				}
909 
910 				if (!compareAndLogBuffer(log, static_cast<size_t>(mappingSize), referenceSize, mapping, &reference[static_cast<size_t>(mappingOffset)]))
911 					result.fail("Unexpected values read from mapped memory.");
912 
913 				if (config.implicitUnmap)
914 				{
915 					AllocationCallbackValidationResults	results;
916 
917 					vkd.freeMemory(device, memory.disown(), allocator);
918 					validateAllocationCallbacks(recorder, &results);
919 
920 					if (!results.liveAllocations.empty())
921 						result.fail("Live allocations remain after freeing mapped memory");
922 				}
923 				else
924 				{
925 					unmapMemoryWrapper(vkd, device, *memory, config.memoryMap2);
926 				}
927 
928 				context.getTestContext().touchWatchdog();
929 			}
930 		}
931 		catch (const tcu::TestError& error)
932 		{
933 			result.fail(error.getMessage());
934 		}
935 	}
936 
937 	if (!atLeastOneTestPerformed)
938 		result.addResult(QP_TEST_RESULT_NOT_SUPPORTED, "No suitable memory kind found to perform test.");
939 
940 	return tcu::TestStatus(result.getResult(), result.getMessage());
941 }
942 
943 class MemoryMapping
944 {
945 public:
946 						MemoryMapping	(const MemoryRange&	range,
947 										 void*				ptr,
948 										 ReferenceMemory&	reference);
949 
950 	void				randomRead		(de::Random& rng);
951 	void				randomWrite		(de::Random& rng);
952 	void				randomModify	(de::Random& rng);
953 
getRange(void) const954 	const MemoryRange&	getRange		(void) const { return m_range; }
955 
956 private:
957 	MemoryRange			m_range;
958 	void*				m_ptr;
959 	ReferenceMemory&	m_reference;
960 };
961 
MemoryMapping(const MemoryRange & range,void * ptr,ReferenceMemory & reference)962 MemoryMapping::MemoryMapping (const MemoryRange&	range,
963 							  void*					ptr,
964 							  ReferenceMemory&		reference)
965 	: m_range		(range)
966 	, m_ptr			(ptr)
967 	, m_reference	(reference)
968 {
969 	DE_ASSERT(range.size > 0);
970 }
971 
randomRead(de::Random & rng)972 void MemoryMapping::randomRead (de::Random& rng)
973 {
974 	const size_t count = (size_t)rng.getInt(0, 100);
975 
976 	for (size_t ndx = 0; ndx < count; ndx++)
977 	{
978 		const size_t	pos	= (size_t)(rng.getUint64() % (deUint64)m_range.size);
979 		const deUint8	val	= ((deUint8*)m_ptr)[pos];
980 
981 		TCU_CHECK(m_reference.read((size_t)(m_range.offset + pos), val));
982 	}
983 }
984 
randomWrite(de::Random & rng)985 void MemoryMapping::randomWrite (de::Random& rng)
986 {
987 	const size_t count = (size_t)rng.getInt(0, 100);
988 
989 	for (size_t ndx = 0; ndx < count; ndx++)
990 	{
991 		const size_t	pos	= (size_t)(rng.getUint64() % (deUint64)m_range.size);
992 		const deUint8	val	= rng.getUint8();
993 
994 		((deUint8*)m_ptr)[pos]	= val;
995 		m_reference.write((size_t)(m_range.offset + pos), val);
996 	}
997 }
998 
randomModify(de::Random & rng)999 void MemoryMapping::randomModify (de::Random& rng)
1000 {
1001 	const size_t count = (size_t)rng.getInt(0, 100);
1002 
1003 	for (size_t ndx = 0; ndx < count; ndx++)
1004 	{
1005 		const size_t	pos		= (size_t)(rng.getUint64() % (deUint64)m_range.size);
1006 		const deUint8	val		= ((deUint8*)m_ptr)[pos];
1007 		const deUint8	mask	= rng.getUint8();
1008 
1009 		((deUint8*)m_ptr)[pos]	= val ^ mask;
1010 		TCU_CHECK(m_reference.modifyXor((size_t)(m_range.offset + pos), val, mask));
1011 	}
1012 }
1013 
randomSize(de::Random & rng,VkDeviceSize atomSize,VkDeviceSize maxSize)1014 VkDeviceSize randomSize (de::Random& rng, VkDeviceSize atomSize, VkDeviceSize maxSize)
1015 {
1016 	const VkDeviceSize maxSizeInAtoms = maxSize / atomSize;
1017 
1018 	DE_ASSERT(maxSizeInAtoms > 0);
1019 
1020 	return maxSizeInAtoms > 1
1021 			? atomSize * (1 + (VkDeviceSize)(rng.getUint64() % (deUint64)maxSizeInAtoms))
1022 			: atomSize;
1023 }
1024 
randomOffset(de::Random & rng,VkDeviceSize atomSize,VkDeviceSize maxOffset)1025 VkDeviceSize randomOffset (de::Random& rng, VkDeviceSize atomSize, VkDeviceSize maxOffset)
1026 {
1027 	const VkDeviceSize maxOffsetInAtoms = maxOffset / atomSize;
1028 
1029 	return maxOffsetInAtoms > 0
1030 			? atomSize * (VkDeviceSize)(rng.getUint64() % (deUint64)(maxOffsetInAtoms + 1))
1031 			: 0;
1032 }
1033 
randomRanges(de::Random & rng,vector<VkMappedMemoryRange> & ranges,size_t count,VkDeviceMemory memory,VkDeviceSize minOffset,VkDeviceSize maxSize,VkDeviceSize atomSize)1034 void randomRanges (de::Random& rng, vector<VkMappedMemoryRange>& ranges, size_t count, VkDeviceMemory memory, VkDeviceSize minOffset, VkDeviceSize maxSize, VkDeviceSize atomSize)
1035 {
1036 	ranges.resize(count);
1037 
1038 	for (size_t rangeNdx = 0; rangeNdx < count; rangeNdx++)
1039 	{
1040 		const VkDeviceSize	size	= randomSize(rng, atomSize, maxSize);
1041 		const VkDeviceSize	offset	= minOffset + randomOffset(rng, atomSize, maxSize - size);
1042 
1043 		const VkMappedMemoryRange range =
1044 		{
1045 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1046 			DE_NULL,
1047 
1048 			memory,
1049 			offset,
1050 			size
1051 		};
1052 		ranges[rangeNdx] = range;
1053 	}
1054 }
1055 
1056 class MemoryObject
1057 {
1058 public:
1059 							MemoryObject			(const DeviceInterface&		vkd,
1060 													 VkDevice					device,
1061 													 VkDeviceSize				size,
1062 													 deUint32					memoryTypeIndex,
1063 													 VkDeviceSize				atomSize,
1064 													 VkDeviceSize				memoryUsage,
1065 													 VkDeviceSize				referenceMemoryUsage);
1066 
1067 							~MemoryObject			(void);
1068 
1069 	MemoryMapping*			mapRandom				(const DeviceInterface& vkd, VkDevice device, de::Random& rng, bool map2);
1070 	void					unmap					(bool map2);
1071 
1072 	void					randomFlush				(const DeviceInterface& vkd, VkDevice device, de::Random& rng);
1073 	void					randomInvalidate		(const DeviceInterface& vkd, VkDevice device, de::Random& rng);
1074 
getSize(void) const1075 	VkDeviceSize			getSize					(void) const { return m_size; }
getMapping(void)1076 	MemoryMapping*			getMapping				(void) { return m_mapping; }
1077 
getMemoryUsage(void) const1078 	VkDeviceSize			getMemoryUsage			(void) const { return m_memoryUsage; }
getReferenceMemoryUsage(void) const1079 	VkDeviceSize			getReferenceMemoryUsage	(void) const { return m_referenceMemoryUsage; }
1080 private:
1081 	const DeviceInterface&	m_vkd;
1082 	const VkDevice			m_device;
1083 
1084 	const deUint32			m_memoryTypeIndex;
1085 	const VkDeviceSize		m_size;
1086 	const VkDeviceSize		m_atomSize;
1087 	const VkDeviceSize		m_memoryUsage;
1088 	const VkDeviceSize		m_referenceMemoryUsage;
1089 
1090 	Move<VkDeviceMemory>	m_memory;
1091 
1092 	MemoryMapping*			m_mapping;
1093 	ReferenceMemory			m_referenceMemory;
1094 };
1095 
MemoryObject(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,deUint32 memoryTypeIndex,VkDeviceSize atomSize,VkDeviceSize memoryUsage,VkDeviceSize referenceMemoryUsage)1096 MemoryObject::MemoryObject (const DeviceInterface&		vkd,
1097 							VkDevice					device,
1098 							VkDeviceSize				size,
1099 							deUint32					memoryTypeIndex,
1100 							VkDeviceSize				atomSize,
1101 							VkDeviceSize				memoryUsage,
1102 							VkDeviceSize				referenceMemoryUsage)
1103 	: m_vkd						(vkd)
1104 	, m_device					(device)
1105 	, m_memoryTypeIndex			(memoryTypeIndex)
1106 	, m_size					(size)
1107 	, m_atomSize				(atomSize)
1108 	, m_memoryUsage				(memoryUsage)
1109 	, m_referenceMemoryUsage	(referenceMemoryUsage)
1110 	, m_mapping					(DE_NULL)
1111 	, m_referenceMemory			((size_t)size, (size_t)m_atomSize)
1112 {
1113 	m_memory = allocMemory(m_vkd, m_device, m_size, m_memoryTypeIndex);
1114 }
1115 
~MemoryObject(void)1116 MemoryObject::~MemoryObject (void)
1117 {
1118 	delete m_mapping;
1119 }
1120 
mapRandom(const DeviceInterface & vkd,VkDevice device,de::Random & rng,bool map2)1121 MemoryMapping* MemoryObject::mapRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng, bool map2)
1122 {
1123 	const VkDeviceSize	size	= randomSize(rng, m_atomSize, m_size);
1124 	const VkDeviceSize	offset	= randomOffset(rng, m_atomSize, m_size - size);
1125 	void*				ptr;
1126 
1127 	DE_ASSERT(!m_mapping);
1128 
1129 	mapMemoryWrapper(vkd, device, *m_memory, offset, size, &ptr, map2);
1130 	TCU_CHECK(ptr);
1131 	m_mapping = new MemoryMapping(MemoryRange(offset, size), ptr, m_referenceMemory);
1132 
1133 	return m_mapping;
1134 }
1135 
unmap(bool map2)1136 void MemoryObject::unmap (bool map2)
1137 {
1138 	unmapMemoryWrapper(m_vkd, m_device, *m_memory, map2);
1139 
1140 	delete m_mapping;
1141 	m_mapping = DE_NULL;
1142 }
1143 
randomFlush(const DeviceInterface & vkd,VkDevice device,de::Random & rng)1144 void MemoryObject::randomFlush (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
1145 {
1146 	const size_t				rangeCount	= (size_t)rng.getInt(1, 10);
1147 	vector<VkMappedMemoryRange>	ranges		(rangeCount);
1148 
1149 	randomRanges(rng, ranges, rangeCount, *m_memory, m_mapping->getRange().offset, m_mapping->getRange().size, m_atomSize);
1150 
1151 	for (size_t rangeNdx = 0; rangeNdx < ranges.size(); rangeNdx++)
1152 		m_referenceMemory.flush((size_t)ranges[rangeNdx].offset, (size_t)ranges[rangeNdx].size);
1153 
1154 	VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
1155 }
1156 
randomInvalidate(const DeviceInterface & vkd,VkDevice device,de::Random & rng)1157 void MemoryObject::randomInvalidate (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
1158 {
1159 	const size_t				rangeCount	= (size_t)rng.getInt(1, 10);
1160 	vector<VkMappedMemoryRange>	ranges		(rangeCount);
1161 
1162 	randomRanges(rng, ranges, rangeCount, *m_memory, m_mapping->getRange().offset, m_mapping->getRange().size, m_atomSize);
1163 
1164 	for (size_t rangeNdx = 0; rangeNdx < ranges.size(); rangeNdx++)
1165 		m_referenceMemory.invalidate((size_t)ranges[rangeNdx].offset, (size_t)ranges[rangeNdx].size);
1166 
1167 	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
1168 }
1169 
1170 enum
1171 {
1172 	MAX_MEMORY_USAGE_DIV = 2, // Use only 1/2 of each memory heap.
1173 	MAX_MEMORY_ALLOC_DIV = 2, // Do not alloc more than 1/2 of available space.
1174 };
1175 
1176 template<typename T>
removeFirstEqual(vector<T> & vec,const T & val)1177 void removeFirstEqual (vector<T>& vec, const T& val)
1178 {
1179 	for (size_t ndx = 0; ndx < vec.size(); ndx++)
1180 	{
1181 		if (vec[ndx] == val)
1182 		{
1183 			vec[ndx] = vec.back();
1184 			vec.pop_back();
1185 			return;
1186 		}
1187 	}
1188 }
1189 
1190 enum MemoryClass
1191 {
1192 	MEMORY_CLASS_SYSTEM = 0,
1193 	MEMORY_CLASS_DEVICE,
1194 
1195 	MEMORY_CLASS_LAST
1196 };
1197 
1198 // \todo [2016-04-20 pyry] Consider estimating memory fragmentation
1199 class TotalMemoryTracker
1200 {
1201 public:
TotalMemoryTracker(void)1202 					TotalMemoryTracker	(void)
1203 	{
1204 		std::fill(DE_ARRAY_BEGIN(m_usage), DE_ARRAY_END(m_usage), 0);
1205 	}
1206 
allocate(MemoryClass memClass,VkDeviceSize size)1207 	void			allocate			(MemoryClass memClass, VkDeviceSize size)
1208 	{
1209 		m_usage[memClass] += size;
1210 	}
1211 
free(MemoryClass memClass,VkDeviceSize size)1212 	void			free				(MemoryClass memClass, VkDeviceSize size)
1213 	{
1214 		DE_ASSERT(size <= m_usage[memClass]);
1215 		m_usage[memClass] -= size;
1216 	}
1217 
getUsage(MemoryClass memClass) const1218 	VkDeviceSize	getUsage			(MemoryClass memClass) const
1219 	{
1220 		return m_usage[memClass];
1221 	}
1222 
getTotalUsage(void) const1223 	VkDeviceSize	getTotalUsage		(void) const
1224 	{
1225 		VkDeviceSize total = 0;
1226 		for (int ndx = 0; ndx < MEMORY_CLASS_LAST; ++ndx)
1227 			total += getUsage((MemoryClass)ndx);
1228 		return total;
1229 	}
1230 
1231 private:
1232 	VkDeviceSize	m_usage[MEMORY_CLASS_LAST];
1233 };
1234 
getHostPageSize(void)1235 VkDeviceSize getHostPageSize (void)
1236 {
1237 	return 4096;
1238 }
1239 
1240 class MemoryHeap
1241 {
1242 public:
MemoryHeap(const VkMemoryHeap & heap,const vector<MemoryType> & memoryTypes,const tcu::PlatformMemoryLimits & memoryLimits,const VkDeviceSize nonCoherentAtomSize,TotalMemoryTracker & totalMemTracker)1243 	MemoryHeap (const VkMemoryHeap&					heap,
1244 				const vector<MemoryType>&			memoryTypes,
1245 				const tcu::PlatformMemoryLimits&	memoryLimits,
1246 				const VkDeviceSize					nonCoherentAtomSize,
1247 				TotalMemoryTracker&					totalMemTracker)
1248 		: m_heap				(heap)
1249 		, m_memoryTypes			(memoryTypes)
1250 		, m_limits				(memoryLimits)
1251 		, m_nonCoherentAtomSize	(nonCoherentAtomSize)
1252 		, m_minAtomSize			(nonCoherentAtomSize)
1253 		, m_totalMemTracker		(totalMemTracker)
1254 		, m_usage				(0)
1255 	{
1256 	}
1257 
~MemoryHeap(void)1258 	~MemoryHeap (void)
1259 	{
1260 		for (vector<MemoryObject*>::iterator iter = m_objects.begin(); iter != m_objects.end(); ++iter)
1261 			delete *iter;
1262 	}
1263 
1264 	bool								full			(void) const;
empty(void) const1265 	bool								empty			(void) const
1266 	{
1267 		return m_usage == 0 && !full();
1268 	}
1269 
1270 	MemoryObject*						allocateRandom	(const DeviceInterface& vkd, VkDevice device, de::Random& rng);
1271 
getRandomObject(de::Random & rng) const1272 	MemoryObject*						getRandomObject	(de::Random& rng) const
1273 	{
1274 		return rng.choose<MemoryObject*>(m_objects.begin(), m_objects.end());
1275 	}
1276 
free(MemoryObject * object)1277 	void								free			(MemoryObject* object)
1278 	{
1279 		removeFirstEqual(m_objects, object);
1280 		m_usage -= object->getMemoryUsage();
1281 		m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, object->getReferenceMemoryUsage());
1282 		m_totalMemTracker.free(getMemoryClass(), object->getMemoryUsage());
1283 		delete object;
1284 	}
1285 
1286 private:
getMemoryClass(void) const1287 	MemoryClass							getMemoryClass	(void) const
1288 	{
1289 		if ((m_heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
1290 			return MEMORY_CLASS_DEVICE;
1291 		else
1292 			return MEMORY_CLASS_SYSTEM;
1293 	}
1294 
1295 	const VkMemoryHeap					m_heap;
1296 	const vector<MemoryType>			m_memoryTypes;
1297 	const tcu::PlatformMemoryLimits&	m_limits;
1298 	const VkDeviceSize					m_nonCoherentAtomSize;
1299 	const VkDeviceSize					m_minAtomSize;
1300 	TotalMemoryTracker&					m_totalMemTracker;
1301 
1302 	VkDeviceSize						m_usage;
1303 	vector<MemoryObject*>				m_objects;
1304 };
1305 
1306 // Heap is full if there is not enough memory to allocate minimal memory object.
full(void) const1307 bool MemoryHeap::full (void) const
1308 {
1309 	DE_ASSERT(m_usage <= m_heap.size/MAX_MEMORY_USAGE_DIV);
1310 
1311 	const VkDeviceSize	availableInHeap		= m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage;
1312 	const bool			isUMA				= m_limits.totalDeviceLocalMemory == 0;
1313 	const MemoryClass	memClass			= getMemoryClass();
1314 	const VkDeviceSize	minAllocationSize	= de::max(m_minAtomSize, memClass == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize());
1315 	// Memory required for reference. One byte and one bit for each byte and one bit per each m_atomSize.
1316 	const VkDeviceSize	minReferenceSize	= minAllocationSize
1317 											+ divRoundUp<VkDeviceSize>(minAllocationSize,  8)
1318 											+ divRoundUp<VkDeviceSize>(minAllocationSize,  m_minAtomSize * 8);
1319 
1320 	if (isUMA)
1321 	{
1322 		const VkDeviceSize	totalUsage	= m_totalMemTracker.getTotalUsage();
1323 		const VkDeviceSize	totalSysMem	= (VkDeviceSize)m_limits.totalSystemMemory;
1324 
1325 		DE_ASSERT(totalUsage <= totalSysMem);
1326 
1327 		return (minAllocationSize + minReferenceSize) > (totalSysMem - totalUsage)
1328 				|| minAllocationSize > availableInHeap;
1329 	}
1330 	else
1331 	{
1332 		const VkDeviceSize	totalUsage		= m_totalMemTracker.getTotalUsage();
1333 		const VkDeviceSize	totalSysMem		= (VkDeviceSize)m_limits.totalSystemMemory;
1334 
1335 		const VkDeviceSize	totalMemClass	= memClass == MEMORY_CLASS_SYSTEM
1336 											? m_limits.totalSystemMemory
1337 											: m_limits.totalDeviceLocalMemory;
1338 		const VkDeviceSize	usedMemClass	= m_totalMemTracker.getUsage(memClass);
1339 
1340 		DE_ASSERT(usedMemClass <= totalMemClass);
1341 
1342 		return minAllocationSize > availableInHeap
1343 				|| minAllocationSize > (totalMemClass - usedMemClass)
1344 				|| minReferenceSize > (totalSysMem - totalUsage);
1345 	}
1346 }
1347 
allocateRandom(const DeviceInterface & vkd,VkDevice device,de::Random & rng)1348 MemoryObject* MemoryHeap::allocateRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
1349 {
1350 	pair<MemoryType, VkDeviceSize> memoryTypeMaxSizePair;
1351 
1352 	// Pick random memory type
1353 	{
1354 		vector<pair<MemoryType, VkDeviceSize> > memoryTypes;
1355 
1356 		const VkDeviceSize	availableInHeap		= m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage;
1357 		const bool			isUMA				= m_limits.totalDeviceLocalMemory == 0;
1358 		const MemoryClass	memClass			= getMemoryClass();
1359 
1360 		// Collect memory types that can be allocated and the maximum size of allocation.
1361 		// Memory type can be only allocated if minimal memory allocation is less than available memory.
1362 		for (size_t memoryTypeNdx = 0; memoryTypeNdx < m_memoryTypes.size(); memoryTypeNdx++)
1363 		{
1364 			const MemoryType	type						= m_memoryTypes[memoryTypeNdx];
1365 			const VkDeviceSize	atomSize					= m_nonCoherentAtomSize;
1366 			const VkDeviceSize	allocationSizeGranularity	= de::max(atomSize, memClass == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize());
1367 			const VkDeviceSize	minAllocationSize			= allocationSizeGranularity;
1368 			const VkDeviceSize	minReferenceSize			= minAllocationSize
1369 															+ divRoundUp<VkDeviceSize>(minAllocationSize,  8)
1370 															+ divRoundUp<VkDeviceSize>(minAllocationSize,  atomSize * 8);
1371 
1372 			if (isUMA)
1373 			{
1374 				// Max memory size calculation is little tricky since reference memory requires 1/n bits per byte.
1375 				const VkDeviceSize	totalUsage				= m_totalMemTracker.getTotalUsage();
1376 				const VkDeviceSize	totalSysMem				= (VkDeviceSize)m_limits.totalSystemMemory;
1377 				const VkDeviceSize	availableBits			= (totalSysMem - totalUsage) * 8;
1378 				// availableBits == maxAllocationSizeBits + maxAllocationReferenceSizeBits
1379 				// maxAllocationReferenceSizeBits == maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits)
1380 				// availableBits == maxAllocationSizeBits + maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits)
1381 				// availableBits == 2 * maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits)
1382 				// availableBits == (2 + 1/8 + 1/atomSizeBits) * maxAllocationSizeBits
1383 				// 8 * availableBits == (16 + 1 + 8/atomSizeBits) * maxAllocationSizeBits
1384 				// atomSizeBits * 8 * availableBits == (17 * atomSizeBits + 8) * maxAllocationSizeBits
1385 				// maxAllocationSizeBits == atomSizeBits * 8 * availableBits / (17 * atomSizeBits + 8)
1386 				// maxAllocationSizeBytes == maxAllocationSizeBits / 8
1387 				// maxAllocationSizeBytes == atomSizeBits * availableBits / (17 * atomSizeBits + 8)
1388 				// atomSizeBits = atomSize * 8
1389 				// maxAllocationSizeBytes == atomSize * 8 * availableBits / (17 * atomSize * 8 + 8)
1390 				// maxAllocationSizeBytes == atomSize * availableBits / (17 * atomSize + 1)
1391 				//
1392 				// Finally, the allocation size must be less than or equal to memory heap size
1393 				const VkDeviceSize	maxAllocationSize		= roundDownToMultiple(de::min((atomSize * availableBits) / (17 * atomSize + 1), availableInHeap), allocationSizeGranularity);
1394 
1395 				DE_ASSERT(totalUsage <= totalSysMem);
1396 				DE_ASSERT(maxAllocationSize <= totalSysMem);
1397 
1398 				if (minAllocationSize + minReferenceSize <= (totalSysMem - totalUsage) && minAllocationSize <= availableInHeap)
1399 				{
1400 					DE_ASSERT(maxAllocationSize >= minAllocationSize);
1401 					memoryTypes.push_back(std::make_pair(type, maxAllocationSize));
1402 				}
1403 			}
1404 			else
1405 			{
1406 				// Max memory size calculation is little tricky since reference memory requires 1/n bits per byte.
1407 				const VkDeviceSize	totalUsage			= m_totalMemTracker.getTotalUsage();
1408 				const VkDeviceSize	totalSysMem			= (VkDeviceSize)m_limits.totalSystemMemory;
1409 
1410 				const VkDeviceSize	totalMemClass		= memClass == MEMORY_CLASS_SYSTEM
1411 														? m_limits.totalSystemMemory
1412 														: m_limits.totalDeviceLocalMemory;
1413 				const VkDeviceSize	usedMemClass		= m_totalMemTracker.getUsage(memClass);
1414 				// availableRefBits = maxRefBits + maxRefBits/8 + maxRefBits/atomSizeBits
1415 				// availableRefBits = maxRefBits * (1 + 1/8 + 1/atomSizeBits)
1416 				// 8 * availableRefBits = maxRefBits * (8 + 1 + 8/atomSizeBits)
1417 				// 8 * atomSizeBits * availableRefBits = maxRefBits * (9 * atomSizeBits + 8)
1418 				// maxRefBits = 8 * atomSizeBits * availableRefBits / (9 * atomSizeBits + 8)
1419 				// atomSizeBits = atomSize * 8
1420 				// maxRefBits = 8 * atomSize * 8 * availableRefBits / (9 * atomSize * 8 + 8)
1421 				// maxRefBits = atomSize * 8 * availableRefBits / (9 * atomSize + 1)
1422 				// maxRefBytes = atomSize * availableRefBits / (9 * atomSize + 1)
1423 				//
1424 				// Finally, the allocation size must be less than or equal to memory heap size
1425 				const VkDeviceSize	maxAllocationSize = roundDownToMultiple(de::min(de::min(totalMemClass - usedMemClass, (atomSize * 8 * (totalSysMem - totalUsage)) / (9 * atomSize + 1)), availableInHeap), allocationSizeGranularity);
1426 
1427 				DE_ASSERT(usedMemClass <= totalMemClass);
1428 
1429 				if (minAllocationSize <= availableInHeap
1430 						&& minAllocationSize <= (totalMemClass - usedMemClass)
1431 						&& minReferenceSize <= (totalSysMem - totalUsage))
1432 				{
1433 					DE_ASSERT(maxAllocationSize >= minAllocationSize);
1434 					memoryTypes.push_back(std::make_pair(type, maxAllocationSize));
1435 				}
1436 
1437 			}
1438 		}
1439 
1440 		memoryTypeMaxSizePair = rng.choose<pair<MemoryType, VkDeviceSize> >(memoryTypes.begin(), memoryTypes.end());
1441 	}
1442 
1443 	const MemoryType		type						= memoryTypeMaxSizePair.first;
1444 	const VkDeviceSize		maxAllocationSize			= memoryTypeMaxSizePair.second / MAX_MEMORY_ALLOC_DIV;
1445 	const VkDeviceSize		atomSize					= m_nonCoherentAtomSize;
1446 	const VkDeviceSize		allocationSizeGranularity	= de::max(atomSize, getMemoryClass() == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize());
1447 	const VkDeviceSize		size						= randomSize(rng, atomSize, maxAllocationSize);
1448 	const VkDeviceSize		memoryUsage					= roundUpToMultiple(size, allocationSizeGranularity);
1449 	const VkDeviceSize		referenceMemoryUsage		= size + divRoundUp<VkDeviceSize>(size, 8) + divRoundUp<VkDeviceSize>(size / atomSize, 8);
1450 
1451 	DE_ASSERT(size <= maxAllocationSize);
1452 
1453 	MemoryObject* const		object	= new MemoryObject(vkd, device, size, type.index, atomSize, memoryUsage, referenceMemoryUsage);
1454 
1455 	m_usage += memoryUsage;
1456 	m_totalMemTracker.allocate(getMemoryClass(), memoryUsage);
1457 	m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, referenceMemoryUsage);
1458 	m_objects.push_back(object);
1459 
1460 	return object;
1461 }
1462 
getMemoryObjectSystemSize(Context & context)1463 size_t getMemoryObjectSystemSize (Context& context)
1464 {
1465 	return computeDeviceMemorySystemMemFootprint(context.getDeviceInterface(), context.getDevice())
1466 		   + sizeof(MemoryObject)
1467 		   + sizeof(de::SharedPtr<MemoryObject>);
1468 }
1469 
getMemoryMappingSystemSize(void)1470 size_t getMemoryMappingSystemSize (void)
1471 {
1472 	return sizeof(MemoryMapping) + sizeof(de::SharedPtr<MemoryMapping>);
1473 }
1474 
1475 struct RandomMappingConfig
1476 {
1477 	deUint32 seed;
1478 	bool memoryMap2;
1479 };
1480 
1481 class RandomMemoryMappingInstance : public TestInstance
1482 {
1483 public:
RandomMemoryMappingInstance(Context & context,const RandomMappingConfig & config)1484 	RandomMemoryMappingInstance (Context& context, const RandomMappingConfig& config)
1485 		: TestInstance				(context)
1486 		, m_memoryObjectSysMemSize	(getMemoryObjectSystemSize(context))
1487 		, m_memoryMappingSysMemSize	(getMemoryMappingSystemSize())
1488 		, m_memoryLimits			(tcu::getMemoryLimits(context.getTestContext().getPlatform()))
1489 		, m_rng						(config.seed)
1490 		, m_opNdx					(0)
1491 		, m_map2					(config.memoryMap2)
1492 	{
1493 		const VkPhysicalDevice					physicalDevice		= context.getPhysicalDevice();
1494 		const InstanceInterface&				vki					= context.getInstanceInterface();
1495 		const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, physicalDevice);
1496 		const VkDeviceSize						nonCoherentAtomSize	= context.getDeviceProperties().limits.nonCoherentAtomSize;
1497 
1498 		// Initialize heaps
1499 		{
1500 			vector<vector<MemoryType> >	memoryTypes	(memoryProperties.memoryHeapCount);
1501 
1502 			for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
1503 			{
1504 				if (memoryProperties.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
1505 					memoryTypes[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].push_back(MemoryType(memoryTypeNdx, memoryProperties.memoryTypes[memoryTypeNdx]));
1506 			}
1507 
1508 			for (deUint32 heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; heapIndex++)
1509 			{
1510 				const VkMemoryHeap	heapInfo	= memoryProperties.memoryHeaps[heapIndex];
1511 
1512 				if (!memoryTypes[heapIndex].empty())
1513 				{
1514 					const de::SharedPtr<MemoryHeap>	heap	(new MemoryHeap(heapInfo, memoryTypes[heapIndex], m_memoryLimits, nonCoherentAtomSize, m_totalMemTracker));
1515 
1516 					TCU_CHECK_INTERNAL(!heap->full());
1517 
1518 					m_memoryHeaps.push_back(heap);
1519 				}
1520 			}
1521 		}
1522 	}
1523 
~RandomMemoryMappingInstance(void)1524 	~RandomMemoryMappingInstance (void)
1525 	{
1526 	}
1527 
iterate(void)1528 	tcu::TestStatus iterate (void)
1529 	{
1530 		const size_t			opCount						= 100;
1531 		const float				memoryOpProbability			= 0.5f;		// 0.50
1532 		const float				flushInvalidateProbability	= 0.4f;		// 0.20
1533 		const float				mapProbability				= 0.50f;	// 0.15
1534 		const float				unmapProbability			= 0.25f;	// 0.075
1535 
1536 		const float				allocProbability			= 0.75f; // Versun free
1537 
1538 		const VkDevice			device						= m_context.getDevice();
1539 		const DeviceInterface&	vkd							= m_context.getDeviceInterface();
1540 
1541 		const VkDeviceSize		sysMemUsage					= (m_memoryLimits.totalDeviceLocalMemory == 0)
1542 															? m_totalMemTracker.getTotalUsage()
1543 															: m_totalMemTracker.getUsage(MEMORY_CLASS_SYSTEM);
1544 
1545 		if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
1546 		{
1547 			// Perform operations on mapped memory
1548 			MemoryMapping* const	mapping	= m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
1549 
1550 			enum Op
1551 			{
1552 				OP_READ = 0,
1553 				OP_WRITE,
1554 				OP_MODIFY,
1555 				OP_LAST
1556 			};
1557 
1558 			const Op op = (Op)(m_rng.getUint32() % OP_LAST);
1559 
1560 			switch (op)
1561 			{
1562 				case OP_READ:
1563 					mapping->randomRead(m_rng);
1564 					break;
1565 
1566 				case OP_WRITE:
1567 					mapping->randomWrite(m_rng);
1568 					break;
1569 
1570 				case OP_MODIFY:
1571 					mapping->randomModify(m_rng);
1572 					break;
1573 
1574 				default:
1575 					DE_FATAL("Invalid operation");
1576 			}
1577 		}
1578 		else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
1579 		{
1580 			MemoryObject* const	object	= m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
1581 
1582 			if (m_rng.getBool())
1583 				object->randomFlush(vkd, device, m_rng);
1584 			else
1585 				object->randomInvalidate(vkd, device, m_rng);
1586 		}
1587 		else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
1588 		{
1589 			// Unmap memory object
1590 			MemoryObject* const	object	= m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
1591 
1592 			// Remove mapping
1593 			removeFirstEqual(m_memoryMappings, object->getMapping());
1594 
1595 			object->unmap(m_map2);
1596 			removeFirstEqual(m_mappedMemoryObjects, object);
1597 			m_nonMappedMemoryObjects.push_back(object);
1598 
1599 			m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
1600 		}
1601 		else if (!m_nonMappedMemoryObjects.empty() &&
1602 				 (m_rng.getFloat() < mapProbability) &&
1603 				 (sysMemUsage+m_memoryMappingSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory))
1604 		{
1605 			// Map memory object
1606 			MemoryObject* const		object	= m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
1607 			MemoryMapping*			mapping	= object->mapRandom(vkd, device, m_rng, m_map2);
1608 
1609 			m_memoryMappings.push_back(mapping);
1610 			m_mappedMemoryObjects.push_back(object);
1611 			removeFirstEqual(m_nonMappedMemoryObjects, object);
1612 
1613 			m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
1614 		}
1615 		else
1616 		{
1617 			// Sort heaps based on capacity (full or not)
1618 			vector<MemoryHeap*>		nonFullHeaps;
1619 			vector<MemoryHeap*>		nonEmptyHeaps;
1620 
1621 			if (sysMemUsage+m_memoryObjectSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory)
1622 			{
1623 				// For the duration of sorting reserve MemoryObject space from system memory
1624 				m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
1625 
1626 				for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
1627 					 heapIter != m_memoryHeaps.end();
1628 					 ++heapIter)
1629 				{
1630 					if (!(*heapIter)->full())
1631 						nonFullHeaps.push_back(heapIter->get());
1632 
1633 					if (!(*heapIter)->empty())
1634 						nonEmptyHeaps.push_back(heapIter->get());
1635 				}
1636 
1637 				m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
1638 			}
1639 			else
1640 			{
1641 				// Not possible to even allocate MemoryObject from system memory, look for non-empty heaps
1642 				for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
1643 					 heapIter != m_memoryHeaps.end();
1644 					 ++heapIter)
1645 				{
1646 					if (!(*heapIter)->empty())
1647 						nonEmptyHeaps.push_back(heapIter->get());
1648 				}
1649 			}
1650 
1651 			if (!nonFullHeaps.empty() && (nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
1652 			{
1653 				// Reserve MemoryObject from sys mem first
1654 				m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
1655 
1656 				// Allocate more memory objects
1657 				MemoryHeap* const	heap	= m_rng.choose<MemoryHeap*>(nonFullHeaps.begin(), nonFullHeaps.end());
1658 				MemoryObject* const	object	= heap->allocateRandom(vkd, device, m_rng);
1659 
1660 				m_nonMappedMemoryObjects.push_back(object);
1661 			}
1662 			else
1663 			{
1664 				// Free memory objects
1665 				MemoryHeap* const		heap	= m_rng.choose<MemoryHeap*>(nonEmptyHeaps.begin(), nonEmptyHeaps.end());
1666 				MemoryObject* const		object	= heap->getRandomObject(m_rng);
1667 
1668 				// Remove mapping
1669 				if (object->getMapping())
1670 				{
1671 					removeFirstEqual(m_memoryMappings, object->getMapping());
1672 					m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, m_memoryMappingSysMemSize);
1673 				}
1674 
1675 				removeFirstEqual(m_mappedMemoryObjects, object);
1676 				removeFirstEqual(m_nonMappedMemoryObjects, object);
1677 
1678 				heap->free(object);
1679 				m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
1680 			}
1681 		}
1682 
1683 		m_opNdx += 1;
1684 		if (m_opNdx == opCount)
1685 			return tcu::TestStatus::pass("Pass");
1686 		else
1687 			return tcu::TestStatus::incomplete();
1688 	}
1689 
1690 private:
1691 	const size_t						m_memoryObjectSysMemSize;
1692 	const size_t						m_memoryMappingSysMemSize;
1693 	const tcu::PlatformMemoryLimits		m_memoryLimits;
1694 
1695 	de::Random							m_rng;
1696 	size_t								m_opNdx;
1697 	bool								m_map2;
1698 
1699 	TotalMemoryTracker					m_totalMemTracker;
1700 	vector<de::SharedPtr<MemoryHeap> >	m_memoryHeaps;
1701 
1702 	vector<MemoryObject*>				m_mappedMemoryObjects;
1703 	vector<MemoryObject*>				m_nonMappedMemoryObjects;
1704 	vector<MemoryMapping*>				m_memoryMappings;
1705 };
1706 
1707 enum Op
1708 {
1709 	OP_NONE = 0,
1710 
1711 	OP_FLUSH,
1712 	OP_SUB_FLUSH,
1713 	OP_SUB_FLUSH_SEPARATE,
1714 	OP_SUB_FLUSH_OVERLAPPING,
1715 
1716 	OP_INVALIDATE,
1717 	OP_SUB_INVALIDATE,
1718 	OP_SUB_INVALIDATE_SEPARATE,
1719 	OP_SUB_INVALIDATE_OVERLAPPING,
1720 
1721 	OP_REMAP,
1722 	OP_IMPLICIT_UNMAP,
1723 
1724 	OP_LAST
1725 };
1726 
subMappedConfig(VkDeviceSize allocationSize,const MemoryRange & mapping,Op op,deUint32 seed,AllocationKind allocationKind,bool memoryMap2)1727 TestConfig subMappedConfig (VkDeviceSize				allocationSize,
1728 							const MemoryRange&			mapping,
1729 							Op							op,
1730 							deUint32					seed,
1731 							AllocationKind				allocationKind,
1732 							bool						memoryMap2)
1733 {
1734 	TestConfig config;
1735 
1736 	config.allocationSize	= allocationSize;
1737 	config.seed				= seed;
1738 	config.mapping			= mapping;
1739 	config.remap			= false;
1740 	config.implicitUnmap	= false;
1741 	config.allocationKind	= allocationKind;
1742 	config.memoryMap2		= memoryMap2;
1743 
1744 	switch (op)
1745 	{
1746 		case OP_NONE:
1747 			break;
1748 
1749 		case OP_REMAP:
1750 			config.remap = true;
1751 			break;
1752 
1753 		case OP_IMPLICIT_UNMAP:
1754 			config.implicitUnmap = true;
1755 			break;
1756 
1757 		case OP_FLUSH:
1758 			config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset, mapping.size));
1759 			break;
1760 
1761 		case OP_SUB_FLUSH:
1762 			DE_ASSERT(mapping.size / 4 > 0);
1763 
1764 			config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset + mapping.size / 4, mapping.size / 2));
1765 			break;
1766 
1767 		case OP_SUB_FLUSH_SEPARATE:
1768 			DE_ASSERT(mapping.size / 2 > 0);
1769 
1770 			config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  2, mapping.size - (mapping.size / 2)));
1771 			config.flushMappings.push_back(MemoryRange(mapping.offset, mapping.size / 2));
1772 
1773 			break;
1774 
1775 		case OP_SUB_FLUSH_OVERLAPPING:
1776 			DE_ASSERT((mapping.size / 3) > 0);
1777 
1778 			config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  3, mapping.size - (mapping.size / 2)));
1779 			config.flushMappings.push_back(MemoryRange(mapping.offset, (2 * mapping.size) / 3));
1780 
1781 			break;
1782 
1783 		case OP_INVALIDATE:
1784 			config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset, mapping.size));
1785 			config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset, mapping.size));
1786 			break;
1787 
1788 		case OP_SUB_INVALIDATE:
1789 			DE_ASSERT(mapping.size / 4 > 0);
1790 
1791 			config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset + mapping.size / 4, mapping.size / 2));
1792 			config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset + mapping.size / 4, mapping.size / 2));
1793 			break;
1794 
1795 		case OP_SUB_INVALIDATE_SEPARATE:
1796 			DE_ASSERT(mapping.size / 2 > 0);
1797 
1798 			config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  2, mapping.size - (mapping.size / 2)));
1799 			config.flushMappings.push_back(MemoryRange(mapping.offset, mapping.size / 2));
1800 
1801 			config.invalidateMappings.push_back(MemoryRange(mapping.offset + mapping.size /  2, mapping.size - (mapping.size / 2)));
1802 			config.invalidateMappings.push_back(MemoryRange(mapping.offset, mapping.size / 2));
1803 
1804 			break;
1805 
1806 		case OP_SUB_INVALIDATE_OVERLAPPING:
1807 			DE_ASSERT((mapping.size / 3) > 0);
1808 
1809 			config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  3, mapping.size - (mapping.size / 2)));
1810 			config.flushMappings.push_back(MemoryRange(mapping.offset, (2 * mapping.size) / 3));
1811 
1812 			config.invalidateMappings.push_back(MemoryRange(mapping.offset + mapping.size /  3, mapping.size - (mapping.size / 2)));
1813 			config.invalidateMappings.push_back(MemoryRange(mapping.offset, (2 * mapping.size) / 3));
1814 
1815 			break;
1816 
1817 		default:
1818 			DE_FATAL("Unknown Op");
1819 			return TestConfig();
1820 	}
1821 	for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
1822 	{
1823 		if (config.flushMappings[ndx].offset + config.flushMappings[ndx].size > mapping.size) {
1824 			config.flushMappings[ndx].size = VK_WHOLE_SIZE;
1825 		}
1826 	}
1827 	for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
1828 	{
1829 		if (config.invalidateMappings[ndx].offset + config.invalidateMappings[ndx].size > mapping.size) {
1830 			config.invalidateMappings[ndx].size = VK_WHOLE_SIZE;
1831 		}
1832 	}
1833 	return config;
1834 }
1835 
fullMappedConfig(VkDeviceSize allocationSize,Op op,deUint32 seed,AllocationKind allocationKind,bool memoryMap2)1836 TestConfig fullMappedConfig (VkDeviceSize	allocationSize,
1837 							 Op				op,
1838 							 deUint32		seed,
1839 							 AllocationKind	allocationKind,
1840 							 bool			memoryMap2)
1841 {
1842 	return subMappedConfig(allocationSize, MemoryRange(0, allocationSize), op, seed, allocationKind, memoryMap2);
1843 }
1844 
1845 template <typename T>
checkMapMemory2Support(Context & context,const T & config)1846 void checkMapMemory2Support (Context& context, const T& config)
1847 {
1848 	if (config.memoryMap2)
1849 		context.requireDeviceFunctionality("VK_KHR_map_memory2");
1850 }
1851 
checkSupport(Context & context,TestConfig config)1852 void checkSupport (Context& context, TestConfig config)
1853 {
1854 	context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
1855 
1856 	if (config.allocationKind == ALLOCATION_KIND_DEDICATED_IMAGE
1857 		|| config.allocationKind == ALLOCATION_KIND_DEDICATED_BUFFER)
1858 	{
1859 		context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
1860 	}
1861 
1862 	checkMapMemory2Support(context, config);
1863 }
1864 
checkSupport(Context & context,RandomMappingConfig config)1865 void checkSupport (Context& context, RandomMappingConfig config)
1866 {
1867 	checkMapMemory2Support(context, config);
1868 }
1869 
1870 } // anonymous
1871 
createMappingTests(tcu::TestContext & testCtx)1872 tcu::TestCaseGroup* createMappingTests (tcu::TestContext& testCtx)
1873 {
1874 	// Memory mapping tests.
1875 	de::MovePtr<tcu::TestCaseGroup>		group							(new tcu::TestCaseGroup(testCtx, "mapping"));
1876 	de::MovePtr<tcu::TestCaseGroup>		dedicated						(new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "Dedicated memory mapping tests."));
1877 	de::MovePtr<tcu::TestCaseGroup>		sets[]							=
1878 	{
1879 		de::MovePtr<tcu::TestCaseGroup> (new tcu::TestCaseGroup(testCtx, "suballocation", "Suballocated memory mapping tests.")),
1880 		de::MovePtr<tcu::TestCaseGroup> (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer dedicated memory mapping tests.")),
1881 		de::MovePtr<tcu::TestCaseGroup> (new tcu::TestCaseGroup(testCtx, "image", "Image dedicated memory mapping tests."))
1882 	};
1883 
1884 	const VkDeviceSize allocationSizes[] =
1885 	{
1886 		0, 33, 257, 4087, 8095, 1*1024*1024 + 1,
1887 	};
1888 
1889 	const VkDeviceSize offsets[] =
1890 	{
1891 		0, 17, 129, 255, 1025, 32*1024+1
1892 	};
1893 
1894 	const VkDeviceSize sizes[] =
1895 	{
1896 		31, 255, 1025, 4085, 1*1024*1024 - 1
1897 	};
1898 
1899 	const struct
1900 	{
1901 		const Op			op;
1902 		const char* const	name;
1903 	} ops[] =
1904 	{
1905 		{ OP_NONE,						"simple"					},
1906 		{ OP_REMAP,						"remap"						},
1907 #ifndef CTS_USES_VULKANSC
1908 // implicit_unmap tests use VkAllocationCallbacks forbidden in Vulkan SC
1909 		{ OP_IMPLICIT_UNMAP,			"implicit_unmap"			},
1910 #endif // CTS_USES_VULKANSC
1911 		{ OP_FLUSH,						"flush"						},
1912 		{ OP_SUB_FLUSH,					"subflush"					},
1913 		{ OP_SUB_FLUSH_SEPARATE,		"subflush_separate"			},
1914 		{ OP_SUB_FLUSH_SEPARATE,		"subflush_overlapping"		},
1915 		{ OP_INVALIDATE,				"invalidate"				},
1916 		{ OP_SUB_INVALIDATE,			"subinvalidate"				},
1917 		{ OP_SUB_INVALIDATE_SEPARATE,	"subinvalidate_separate"	},
1918 		{ OP_SUB_INVALIDATE_SEPARATE,	"subinvalidate_overlapping"	}
1919 	};
1920 
1921 	const struct
1922 	{
1923 		    const bool  memoryMap2;
1924 		    const char* nameSuffix;
1925 	} mapFunctions[] =
1926 	{
1927 	    { false, ""      },
1928 	    { true,  "_map2" },
1929 	};
1930 
1931 	// .full
1932 	for (size_t allocationKindNdx = 0; allocationKindNdx < ALLOCATION_KIND_LAST; allocationKindNdx++)
1933 	{
1934 		de::MovePtr<tcu::TestCaseGroup> fullGroup (new tcu::TestCaseGroup(testCtx, "full", "Map memory completely."));
1935 
1936 		for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
1937 		{
1938 			const VkDeviceSize				allocationSize		= allocationSizes[allocationSizeNdx];
1939 			const string					sizeGroupName		= (allocationSize == 0) ? "variable" : de::toString(allocationSize);
1940 			de::MovePtr<tcu::TestCaseGroup>	allocationSizeGroup	(new tcu::TestCaseGroup(testCtx, sizeGroupName.c_str()));
1941 
1942 			for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
1943 			{
1944 				const Op			op		= ops[opNdx].op;
1945 
1946 				// implicit_unmap ignores allocationSize
1947 				if (((allocationSize == 0) && (op != OP_IMPLICIT_UNMAP)) ||
1948 					((allocationSize != 0) && (op == OP_IMPLICIT_UNMAP)))
1949 					continue;
1950 
1951 				for (auto function : mapFunctions)
1952 				{
1953 					std::string			name		= ops[opNdx].name + std::string(function.nameSuffix);
1954 					const deUint32		seed		= (deUint32)(opNdx * allocationSizeNdx);
1955 					const TestConfig	config		= fullMappedConfig(allocationSize, op, seed, static_cast<AllocationKind>(allocationKindNdx), function.memoryMap2);
1956 
1957 					addFunctionCase(allocationSizeGroup.get(), name, checkSupport, testMemoryMapping, config);
1958 				}
1959 			}
1960 
1961 			fullGroup->addChild(allocationSizeGroup.release());
1962 		}
1963 
1964 		sets[allocationKindNdx]->addChild(fullGroup.release());
1965 	}
1966 
1967 	// .sub
1968 	for (size_t allocationKindNdx = 0; allocationKindNdx < ALLOCATION_KIND_LAST; allocationKindNdx++)
1969 	{
1970 		de::MovePtr<tcu::TestCaseGroup> subGroup (new tcu::TestCaseGroup(testCtx, "sub", "Map part of the memory."));
1971 
1972 		for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
1973 		{
1974 			const VkDeviceSize				allocationSize		= allocationSizes[allocationSizeNdx];
1975 			const string					sizeGroupName		= (allocationSize == 0) ? "variable" : de::toString(allocationSize);
1976 			de::MovePtr<tcu::TestCaseGroup>	allocationSizeGroup	(new tcu::TestCaseGroup(testCtx, sizeGroupName.c_str()));
1977 
1978 			for (size_t offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++)
1979 			{
1980 				const VkDeviceSize				offset			= offsets[offsetNdx];
1981 
1982 				if (offset >= allocationSize)
1983 					continue;
1984 
1985 				de::MovePtr<tcu::TestCaseGroup>	offsetGroup		(new tcu::TestCaseGroup(testCtx, ("offset_" + de::toString(offset)).c_str()));
1986 
1987 				for (size_t sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); sizeNdx++)
1988 				{
1989 					const VkDeviceSize				size		= sizes[sizeNdx];
1990 
1991 					if (offset + size > allocationSize)
1992 						continue;
1993 
1994 					if (offset == 0 && size == allocationSize)
1995 						continue;
1996 
1997 					de::MovePtr<tcu::TestCaseGroup>	sizeGroup	(new tcu::TestCaseGroup(testCtx, ("size_" + de::toString(size)).c_str()));
1998 
1999 					for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
2000 					{
2001 						const Op			op		= ops[opNdx].op;
2002 
2003 						// implicit_unmap ignores allocationSize
2004 						if (((allocationSize == 0) && (op != OP_IMPLICIT_UNMAP)) ||
2005 							((allocationSize != 0) && (op == OP_IMPLICIT_UNMAP)))
2006 							continue;
2007 
2008 						const deUint32		seed	= (deUint32)(opNdx * allocationSizeNdx);
2009 
2010 						for (auto function : mapFunctions)
2011 						{
2012 							std::string			name		= ops[opNdx].name + std::string(function.nameSuffix);
2013 							const TestConfig	config	= subMappedConfig(allocationSize, MemoryRange(offset, size), op, seed,
2014 								static_cast<AllocationKind>(allocationKindNdx), function.memoryMap2);
2015 
2016 							addFunctionCase(sizeGroup.get(), name, checkSupport, testMemoryMapping, config);
2017 						}
2018 					}
2019 
2020 					offsetGroup->addChild(sizeGroup.release());
2021 				}
2022 
2023 				allocationSizeGroup->addChild(offsetGroup.release());
2024 			}
2025 
2026 			subGroup->addChild(allocationSizeGroup.release());
2027 		}
2028 
2029 		sets[allocationKindNdx]->addChild(subGroup.release());
2030 	}
2031 
2032 	// .random
2033 	{
2034 		de::MovePtr<tcu::TestCaseGroup>	randomGroup	(new tcu::TestCaseGroup(testCtx, "random", "Random memory mapping tests."));
2035 		de::Random						rng			(3927960301u);
2036 		for (size_t ndx = 0; ndx < 100; ndx++)
2037 		{
2038 			const deUint32		seed	= rng.getUint32();
2039 
2040 			for (auto function : mapFunctions)
2041 			{
2042 				std::string	name	= de::toString(ndx) + std::string(function.nameSuffix);
2043 				const RandomMappingConfig config =
2044 				{
2045 					seed, function.memoryMap2
2046 				};
2047 				randomGroup->addChild(new InstanceFactory1WithSupport<RandomMemoryMappingInstance, RandomMappingConfig, FunctionSupport1<RandomMappingConfig>>
2048 					(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, config, typename FunctionSupport1<RandomMappingConfig>::Args(checkSupport, config)));
2049 			}
2050 		}
2051 
2052 		sets[static_cast<deUint32>(ALLOCATION_KIND_SUBALLOCATED)]->addChild(randomGroup.release());
2053 	}
2054 
2055 	group->addChild(sets[0].release());
2056 	dedicated->addChild(sets[1].release());
2057 	dedicated->addChild(sets[2].release());
2058 	group->addChild(dedicated.release());
2059 
2060 	return group.release();
2061 }
2062 
2063 } // memory
2064 } // vkt
2065