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