CTS Memory tests fix invalid allocation sizes
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / memory / vktMemoryMappingTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and/or associated documentation files (the
9  * "Materials"), to deal in the Materials without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Materials, and to
12  * permit persons to whom the Materials are furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice(s) and this permission notice shall be
16  * included in all copies or substantial portions of the Materials.
17  *
18  * The Materials are Confidential Information as defined by the
19  * Khronos Membership Agreement until designated non-confidential by
20  * Khronos, at which point this condition clause shall be removed.
21  *
22  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
29  *
30  *//*!
31  * \file
32  * \brief Simple memory mapping tests.
33  *//*--------------------------------------------------------------------*/
34
35 #include "vktMemoryMappingTests.hpp"
36
37 #include "vktTestCaseUtil.hpp"
38
39 #include "tcuMaybe.hpp"
40 #include "tcuResultCollector.hpp"
41 #include "tcuTestLog.hpp"
42
43 #include "vkDeviceUtil.hpp"
44 #include "vkPlatform.hpp"
45 #include "vkQueryUtil.hpp"
46 #include "vkRef.hpp"
47 #include "vkStrUtil.hpp"
48
49 #include "deRandom.hpp"
50 #include "deSharedPtr.hpp"
51 #include "deStringUtil.hpp"
52 #include "deUniquePtr.hpp"
53
54 #include <string>
55 #include <vector>
56
57 using tcu::Maybe;
58 using tcu::TestLog;
59
60 using de::SharedPtr;
61
62 using std::string;
63 using std::vector;
64
65 using namespace vk;
66
67 namespace vkt
68 {
69 namespace memory
70 {
71 namespace
72 {
73 Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, VkDeviceSize pAllocInfo_allocationSize, deUint32 pAllocInfo_memoryTypeIndex)
74 {
75         VkDeviceMemory object = 0;
76         const VkMemoryAllocateInfo pAllocInfo =
77         {
78                 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
79                 DE_NULL,
80                 pAllocInfo_allocationSize,
81                 pAllocInfo_memoryTypeIndex,
82         };
83         VK_CHECK(vk.allocateMemory(device, &pAllocInfo, (const VkAllocationCallbacks*)DE_NULL, &object));
84         return Move<VkDeviceMemory>(check<VkDeviceMemory>(object), Deleter<VkDeviceMemory>(vk, device, (const VkAllocationCallbacks*)DE_NULL));
85 }
86
87 struct MemoryRange
88 {
89         MemoryRange (VkDeviceSize offset_ = ~(VkDeviceSize)0, VkDeviceSize size_ = ~(VkDeviceSize)0)
90                 : offset        (offset_)
91                 , size          (size_)
92         {
93         }
94
95         VkDeviceSize    offset;
96         VkDeviceSize    size;
97 };
98
99 struct TestConfig
100 {
101         TestConfig (void)
102                 : allocationSize        (~(VkDeviceSize)0)
103         {
104         }
105
106         VkDeviceSize            allocationSize;
107         deUint32                        seed;
108
109         MemoryRange                     mapping;
110         vector<MemoryRange>     flushMappings;
111         vector<MemoryRange>     invalidateMappings;
112         bool                            remap;
113 };
114
115 bool compareAndLogBuffer (TestLog& log, size_t size, const deUint8* result, const deUint8* reference)
116 {
117         size_t  failedBytes     = 0;
118         size_t  firstFailed     = (size_t)-1;
119
120         for (size_t ndx = 0; ndx < size; ndx++)
121         {
122                 if (result[ndx] != reference[ndx])
123                 {
124                         failedBytes++;
125
126                         if (firstFailed == (size_t)-1)
127                                 firstFailed = ndx;
128                 }
129         }
130
131         if (failedBytes > 0)
132         {
133                 log << TestLog::Message << "Comparison failed. Failed bytes " << failedBytes << ". First failed at offset " << firstFailed << "." << TestLog::EndMessage;
134
135                 std::ostringstream      expectedValues;
136                 std::ostringstream      resultValues;
137
138                 for (size_t ndx = firstFailed; ndx < firstFailed + 10 && ndx < size; ndx++)
139                 {
140                         if (ndx != firstFailed)
141                         {
142                                 expectedValues << ", ";
143                                 resultValues << ", ";
144                         }
145
146                         expectedValues << reference[ndx];
147                         resultValues << result[ndx];
148                 }
149
150                 if (firstFailed + 10 < size)
151                 {
152                         expectedValues << "...";
153                         resultValues << "...";
154                 }
155
156                 log << TestLog::Message << "Expected values at offset: " << firstFailed << ", " << expectedValues.str() << TestLog::EndMessage;
157                 log << TestLog::Message << "Result values at offset: " << firstFailed << ", " << resultValues.str() << TestLog::EndMessage;
158
159                 return false;
160         }
161         else
162                 return true;
163 }
164
165 tcu::TestStatus testMemoryMapping (Context& context, const TestConfig config)
166 {
167         TestLog&                                                                log                                     = context.getTestContext().getLog();
168         tcu::ResultCollector                                    result                          (log);
169         const VkPhysicalDevice                                  physicalDevice          = context.getPhysicalDevice();
170         const VkDevice                                                  device                          = context.getDevice();
171         const InstanceInterface&                                vki                                     = context.getInstanceInterface();
172         const DeviceInterface&                                  vkd                                     = context.getDeviceInterface();
173         const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
174
175         {
176                 const tcu::ScopedLogSection     section (log, "TestCaseInfo", "TestCaseInfo");
177
178                 log << TestLog::Message << "Seed: " << config.seed << TestLog::EndMessage;
179                 log << TestLog::Message << "Allocation size: " << config.allocationSize << TestLog::EndMessage;
180                 log << TestLog::Message << "Mapping, offset: " << config.mapping.offset << ", size: " << config.mapping.size << TestLog::EndMessage;
181
182                 if (!config.flushMappings.empty())
183                 {
184                         log << TestLog::Message << "Invalidating following ranges:" << TestLog::EndMessage;
185
186                         for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
187                                 log << TestLog::Message << "\tOffset: " << config.flushMappings[ndx].offset << ", Size: " << config.flushMappings[ndx].size << TestLog::EndMessage;
188                 }
189
190                 if (config.remap)
191                         log << TestLog::Message << "Remapping memory between flush and invalidation." << TestLog::EndMessage;
192
193                 if (!config.invalidateMappings.empty())
194                 {
195                         log << TestLog::Message << "Flushing following ranges:" << TestLog::EndMessage;
196
197                         for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
198                                 log << TestLog::Message << "\tOffset: " << config.invalidateMappings[ndx].offset << ", Size: " << config.invalidateMappings[ndx].size << TestLog::EndMessage;
199                 }
200         }
201
202         for (deUint32 memoryTypeIndex = 0; memoryTypeIndex < memoryProperties.memoryTypeCount; memoryTypeIndex++)
203         {
204                 try
205                 {
206                         const tcu::ScopedLogSection             section         (log, "MemoryType" + de::toString(memoryTypeIndex), "MemoryType" + de::toString(memoryTypeIndex));
207                         const VkMemoryType&                             memoryType      = memoryProperties.memoryTypes[memoryTypeIndex];
208                         const VkMemoryHeap&                             memoryHeap      = memoryProperties.memoryHeaps[memoryType.heapIndex];
209
210                         log << TestLog::Message << "MemoryType: " << memoryType << TestLog::EndMessage;
211                         log << TestLog::Message << "MemoryHeap: " << memoryHeap << TestLog::EndMessage;
212
213                         if ((memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
214                         {
215                                 log << TestLog::Message << "Memory type doesn't support mapping." << TestLog::EndMessage;
216                         }
217                         else
218                         {
219                                 const Unique<VkDeviceMemory>    memory                          (allocMemory(vkd, device, config.allocationSize, memoryTypeIndex));
220                                 de::Random                                              rng                                     (config.seed);
221                                 vector<deUint8>                                 reference                       ((size_t)config.allocationSize);
222                                 deUint8*                                                mapping                         = DE_NULL;
223
224                                 {
225                                         void* ptr;
226                                         VK_CHECK(vkd.mapMemory(device, *memory, config.mapping.offset, config.mapping.size, 0u, &ptr));
227                                         TCU_CHECK(ptr);
228
229                                         mapping = (deUint8*)ptr;
230                                 }
231
232                                 for (VkDeviceSize ndx = 0; ndx < config.mapping.size; ndx++)
233                                 {
234                                         const deUint8 val = rng.getUint8();
235
236                                         mapping[ndx]                                                                            = val;
237                                         reference[(size_t)(config.mapping.offset + ndx)]        = val;
238                                 }
239
240                                 if (!config.flushMappings.empty())
241                                 {
242                                         vector<VkMappedMemoryRange> ranges;
243
244                                         for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
245                                         {
246                                                 const VkMappedMemoryRange range =
247                                                 {
248                                                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
249                                                         DE_NULL,
250
251                                                         *memory,
252                                                         config.flushMappings[ndx].offset,
253                                                         config.flushMappings[ndx].size
254                                                 };
255
256                                                 ranges.push_back(range);
257                                         }
258
259                                         VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), &ranges[0]));
260                                 }
261
262                                 if (config.remap)
263                                 {
264                                         void* ptr;
265                                         vkd.unmapMemory(device, *memory);
266                                         VK_CHECK(vkd.mapMemory(device, *memory, config.mapping.offset, config.mapping.size, 0u, &ptr));
267                                         TCU_CHECK(ptr);
268
269                                         mapping = (deUint8*)ptr;
270                                 }
271
272                                 if (!config.invalidateMappings.empty())
273                                 {
274                                         vector<VkMappedMemoryRange> ranges;
275
276                                         for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
277                                         {
278                                                 const VkMappedMemoryRange range =
279                                                 {
280                                                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
281                                                         DE_NULL,
282
283                                                         *memory,
284                                                         config.invalidateMappings[ndx].offset,
285                                                         config.invalidateMappings[ndx].size
286                                                 };
287
288                                                 ranges.push_back(range);
289                                         }
290
291                                         VK_CHECK(vkd.invalidateMappedMemoryRanges(device, (deUint32)ranges.size(), &ranges[0]));
292                                 }
293
294                                 if (!compareAndLogBuffer(log, (size_t)config.mapping.size, mapping, &reference[(size_t)config.mapping.offset]))
295                                         result.fail("Unexpected values read from mapped memory.");
296
297                                 vkd.unmapMemory(device, *memory);
298                         }
299                 }
300                 catch (const tcu::TestError& error)
301                 {
302                         result.fail(error.getMessage());
303                 }
304         }
305
306         return tcu::TestStatus(result.getResult(), result.getMessage());
307 }
308
309 class MemoryMapping
310 {
311 public:
312                                 MemoryMapping   (const MemoryRange&     range,
313                                                                  void*                          ptr,
314                                                                  deUint16*                      refPtr);
315
316         void            randomRead              (de::Random& rng);
317         void            randomWrite             (de::Random& rng);
318         void            randomModify    (de::Random& rng);
319
320 private:
321         MemoryRange     m_range;
322         void*           m_ptr;
323         deUint16*       m_refPtr;
324 };
325
326 MemoryMapping::MemoryMapping (const MemoryRange&        range,
327                                                           void*                                 ptr,
328                                                           deUint16*                             refPtr)
329         : m_range       (range)
330         , m_ptr         (ptr)
331         , m_refPtr      (refPtr)
332 {
333         DE_ASSERT(range.size > 0);
334 }
335
336 void MemoryMapping::randomRead (de::Random& rng)
337 {
338         const size_t count = (size_t)rng.getInt(0, 100);
339
340         for (size_t ndx = 0; ndx < count; ndx++)
341         {
342                 const size_t    pos     = (size_t)(rng.getUint64() % (deUint64)m_range.size);
343                 const deUint8   val     = ((deUint8*) m_ptr)[pos];
344
345                 if (m_refPtr[pos] < 256)
346                         TCU_CHECK((deUint16)val == m_refPtr[pos]);
347                 else
348                         m_refPtr[pos] = (deUint16)val;
349         }
350 }
351
352 void MemoryMapping::randomWrite (de::Random& rng)
353 {
354         const size_t count = (size_t)rng.getInt(0, 100);
355
356         for (size_t ndx = 0; ndx < count; ndx++)
357         {
358                 const size_t    pos     = (size_t)(rng.getUint64() % (deUint64)m_range.size);
359                 const deUint8   val     = rng.getUint8();
360
361                 ((deUint8*)m_ptr)[pos]  = val;
362                 m_refPtr[pos]                   = (deUint16)val;
363         }
364 }
365
366 void MemoryMapping::randomModify (de::Random& rng)
367 {
368         const size_t count = (size_t)rng.getInt(0, 100);
369
370         for (size_t ndx = 0; ndx < count; ndx++)
371         {
372                 const size_t    pos             = (size_t)(rng.getUint64() % (deUint64)m_range.size);
373                 const deUint8   val             = ((deUint8*)m_ptr)[pos];
374                 const deUint8   mask    = rng.getUint8();
375
376                 if (m_refPtr[pos] < 256)
377                         TCU_CHECK((deUint16)val == m_refPtr[pos]);
378
379                 ((deUint8*)m_ptr)[pos]  = val ^ mask;
380                 m_refPtr[pos]                   = (deUint16)(val ^ mask);
381         }
382 }
383
384 void randomRanges (de::Random& rng, vector<VkMappedMemoryRange>& ranges, size_t count, VkDeviceMemory memory, VkDeviceSize maxSize)
385 {
386         ranges.resize(count);
387
388         for (size_t rangeNdx = 0; rangeNdx < count; rangeNdx++)
389         {
390                 const VkDeviceSize      size    = (maxSize > 1 ? (VkDeviceSize)(1 + (rng.getUint64() % (deUint64)(maxSize - 1))) : 1);
391                 const VkDeviceSize      offset  = (VkDeviceSize)(rng.getUint64() % (deUint64)(maxSize - size + 1));
392
393                 const VkMappedMemoryRange range =
394                 {
395                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
396                         DE_NULL,
397
398                         memory,
399                         offset,
400                         size
401                 };
402                 ranges[rangeNdx] = range;
403         }
404 }
405
406 class MemoryObject
407 {
408 public:
409                                                         MemoryObject            (const DeviceInterface&         vkd,
410                                                                                                  VkDevice                                       device,
411                                                                                                  VkDeviceSize                           size,
412                                                                                                  deUint32                                       memoryTypeIndex);
413
414                                                         ~MemoryObject           (void);
415
416         MemoryMapping*                  mapRandom                       (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
417         void                                    unmap                           (void);
418
419         void                                    randomFlush                     (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
420         void                                    randomInvalidate        (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
421
422         VkDeviceSize                    getSize                         (void) const { return m_size; }
423         MemoryMapping*                  getMapping                      (void) { return m_mapping; }
424
425 private:
426         const DeviceInterface&  m_vkd;
427         VkDevice                                m_device;
428
429         deUint32                                m_memoryTypeIndex;
430         VkDeviceSize                    m_size;
431
432         Move<VkDeviceMemory>    m_memory;
433
434         MemoryMapping*                  m_mapping;
435         vector<deUint16>                m_reference;
436 };
437
438 MemoryObject::MemoryObject (const DeviceInterface&              vkd,
439                                                         VkDevice                                        device,
440                                                         VkDeviceSize                            size,
441                                                         deUint32                                        memoryTypeIndex)
442         : m_vkd                         (vkd)
443         , m_device                      (device)
444         , m_memoryTypeIndex     (memoryTypeIndex)
445         , m_size                        (size)
446         , m_mapping                     (DE_NULL)
447 {
448         m_memory = allocMemory(m_vkd, m_device, m_size, m_memoryTypeIndex);
449         m_reference.resize((size_t)m_size, 0xFFFFu);
450 }
451
452 MemoryObject::~MemoryObject (void)
453 {
454         delete m_mapping;
455 }
456
457 MemoryMapping* MemoryObject::mapRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
458 {
459         const VkDeviceSize      size    = (m_size > 1 ? (VkDeviceSize)(1 + (rng.getUint64() % (deUint64)(m_size - 1))) : 1);
460         const VkDeviceSize      offset  = (VkDeviceSize)(rng.getUint64() % (deUint64)(m_size - size + 1));
461         void*                           ptr;
462
463         DE_ASSERT(!m_mapping);
464
465         VK_CHECK(vkd.mapMemory(device, *m_memory, offset, size, 0u, &ptr));
466         TCU_CHECK(ptr);
467         m_mapping = new MemoryMapping(MemoryRange(offset, size), ptr, &(m_reference[(size_t)offset]));
468
469         return m_mapping;
470 }
471
472 void MemoryObject::unmap (void)
473 {
474         m_vkd.unmapMemory(m_device, *m_memory);
475
476         delete m_mapping;
477         m_mapping = DE_NULL;
478 }
479
480 void MemoryObject::randomFlush (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
481 {
482         const size_t                            rangeCount      = (size_t)rng.getInt(1, 10);
483         vector<VkMappedMemoryRange>     ranges          (rangeCount);
484
485         randomRanges(rng, ranges, rangeCount, *m_memory, m_size);
486
487         VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
488 }
489
490 void MemoryObject::randomInvalidate (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
491 {
492         const size_t                            rangeCount      = (size_t)rng.getInt(1, 10);
493         vector<VkMappedMemoryRange>     ranges          (rangeCount);
494
495         randomRanges(rng, ranges, rangeCount, *m_memory, m_size);
496
497         VK_CHECK(vkd.invalidateMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
498 }
499
500 enum
501 {
502         // Use only 1/16 of each memory heap.
503         MAX_MEMORY_USAGE_DIV = 16
504 };
505
506 template<typename T>
507 void removeFirstEqual (vector<T>& vec, const T& val)
508 {
509         for (size_t ndx = 0; ndx < vec.size(); ndx++)
510         {
511                 if (vec[ndx] == val)
512                 {
513                         vec[ndx] = vec.back();
514                         vec.pop_back();
515                         return;
516                 }
517         }
518 }
519
520 class MemoryHeap
521 {
522 public:
523         MemoryHeap (const VkMemoryHeap&                 heap,
524                                 const vector<deUint32>&         memoryTypes)
525                 : m_heap                (heap)
526                 , m_memoryTypes (memoryTypes)
527                 , m_usage               (0)
528         {
529         }
530
531         ~MemoryHeap (void)
532         {
533                 for (vector<MemoryObject*>::iterator iter = m_objects.begin(); iter != m_objects.end(); ++iter)
534                         delete *iter;
535         }
536
537         bool                                                            full                    (void) const { return m_usage * MAX_MEMORY_USAGE_DIV >= m_heap.size; }
538         bool                                                            empty                   (void) const { return m_usage == 0; }
539
540         MemoryObject*                                           allocateRandom  (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
541         {
542                 const VkDeviceSize              size    = 1 + (rng.getUint64() % (de::max((deInt64)((m_heap.size / MAX_MEMORY_USAGE_DIV) - m_usage - 1ull), (deInt64)1)));
543                 const deUint32                  type    = rng.choose<deUint32>(m_memoryTypes.begin(), m_memoryTypes.end());
544
545                 if ( (size > (VkDeviceSize)((m_heap.size / MAX_MEMORY_USAGE_DIV) - m_usage)) && (size != 1))
546                         TCU_THROW(InternalError, "Test Error: trying to allocate memory more than the available heap size.");
547
548                 MemoryObject* const             object  = new MemoryObject(vkd, device, size, type);
549
550                 m_usage += size;
551                 m_objects.push_back(object);
552
553                 return object;
554         }
555
556         MemoryObject*                                           getRandomObject (de::Random& rng) const
557         {
558                 return rng.choose<MemoryObject*>(m_objects.begin(), m_objects.end());
559         }
560
561         void                                                            free                    (MemoryObject* object)
562         {
563                 removeFirstEqual(m_objects, object);
564                 m_usage -= object->getSize();
565                 delete object;
566         }
567
568 private:
569         VkMemoryHeap                    m_heap;
570         vector<deUint32>                m_memoryTypes;
571
572         VkDeviceSize                    m_usage;
573         vector<MemoryObject*>   m_objects;
574 };
575
576 class RandomMemoryMappingInstance : public TestInstance
577 {
578 public:
579         RandomMemoryMappingInstance (Context& context, deUint32 seed)
580                 : TestInstance  (context)
581                 , m_rng                 (seed)
582                 , m_opNdx               (0)
583         {
584                 const VkPhysicalDevice                                  physicalDevice          = context.getPhysicalDevice();
585                 const InstanceInterface&                                vki                                     = context.getInstanceInterface();
586                 const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
587
588                 // Initialize heaps
589                 {
590                         vector<vector<deUint32> >       memoryTypes     (memoryProperties.memoryHeapCount);
591
592                         for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
593                         {
594                                 if (memoryProperties.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
595                                         memoryTypes[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].push_back(memoryTypeNdx);
596                         }
597
598                         for (deUint32 heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; heapIndex++)
599                         {
600                                 const VkMemoryHeap      heapInfo        = memoryProperties.memoryHeaps[heapIndex];
601
602                                 if (!memoryTypes[heapIndex].empty())
603                                 {
604                                         const de::SharedPtr<MemoryHeap> heap    (new MemoryHeap(heapInfo, memoryTypes[heapIndex]));
605
606                                         if (!heap->full())
607                                                 m_nonFullHeaps.push_back(heap);
608                                 }
609                         }
610                 }
611         }
612
613         ~RandomMemoryMappingInstance (void)
614         {
615         }
616
617         tcu::TestStatus iterate (void)
618         {
619                 const size_t                    opCount                                         = 100;
620                 const float                             memoryOpProbability                     = 0.5f;         // 0.50
621                 const float                             flushInvalidateProbability      = 0.4f;         // 0.20
622                 const float                             mapProbability                          = 0.50f;        // 0.15
623                 const float                             unmapProbability                        = 0.25f;        // 0.075
624
625                 const float                             allocProbability                        = 0.75f; // Versun free
626
627                 const VkDevice                  device                                          = m_context.getDevice();
628                 const DeviceInterface&  vkd                                                     = m_context.getDeviceInterface();
629
630                 if (m_opNdx < opCount)
631                 {
632                         if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
633                         {
634                                 // Perform operations on mapped memory
635                                 MemoryMapping* const    mapping = m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
636
637                                 enum Op
638                                 {
639                                         OP_READ = 0,
640                                         OP_WRITE,
641                                         OP_MODIFY,
642                                         OP_LAST
643                                 };
644
645                                 const Op op = (Op)(m_rng.getUint32() % OP_LAST);
646
647                                 switch (op)
648                                 {
649                                         case OP_READ:
650                                                 mapping->randomRead(m_rng);
651                                                 break;
652
653                                         case OP_WRITE:
654                                                 mapping->randomWrite(m_rng);
655                                                 break;
656
657                                         case OP_MODIFY:
658                                                 mapping->randomModify(m_rng);
659                                                 break;
660
661                                         default:
662                                                 DE_FATAL("Invalid operation");
663                                 }
664                         }
665                         else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
666                         {
667                                 MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
668
669                                 if (m_rng.getBool())
670                                         object->randomFlush(vkd, device, m_rng);
671                                 else
672                                         object->randomInvalidate(vkd, device, m_rng);
673                         }
674                         else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
675                         {
676                                 // Unmap memory object
677                                 MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
678
679                                 // Remove mapping
680                                 removeFirstEqual(m_memoryMappings, object->getMapping());
681
682                                 object->unmap();
683                                 removeFirstEqual(m_mappedMemoryObjects, object);
684                                 m_nonMappedMemoryObjects.push_back(object);
685                         }
686                         else if (!m_nonMappedMemoryObjects.empty() && m_rng.getFloat() < mapProbability)
687                         {
688                                 // Map memory object
689                                 MemoryObject* const             object  = m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
690                                 MemoryMapping*                  mapping = object->mapRandom(vkd, device, m_rng);
691
692                                 m_memoryMappings.push_back(mapping);
693                                 m_mappedMemoryObjects.push_back(object);
694                                 removeFirstEqual(m_nonMappedMemoryObjects, object);
695                         }
696                         else
697                         {
698                                 if (!m_nonFullHeaps.empty() && (m_nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
699                                 {
700                                         // Allocate more memory objects
701                                         de::SharedPtr<MemoryHeap> const heap = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonFullHeaps.begin(), m_nonFullHeaps.end());
702
703                                         if (heap->empty())
704                                                 m_nonEmptyHeaps.push_back(heap);
705
706                                         {
707                                                 MemoryObject* const     object = heap->allocateRandom(vkd, device, m_rng);
708
709                                                 if (heap->full())
710                                                         removeFirstEqual(m_nonFullHeaps, heap);
711
712                                                 m_nonMappedMemoryObjects.push_back(object);
713                                         }
714                                 }
715                                 else
716                                 {
717                                         // Free memory objects
718                                         de::SharedPtr<MemoryHeap> const         heap    = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonEmptyHeaps.begin(), m_nonEmptyHeaps.end());
719                                         MemoryObject* const                                     object  = heap->getRandomObject(m_rng);
720
721                                         // Remove mapping
722                                         if (object->getMapping())
723                                                 removeFirstEqual(m_memoryMappings, object->getMapping());
724
725                                         removeFirstEqual(m_mappedMemoryObjects, object);
726                                         removeFirstEqual(m_nonMappedMemoryObjects, object);
727
728                                         if (heap->full())
729                                                 m_nonFullHeaps.push_back(heap);
730
731                                         heap->free(object);
732
733                                         if (heap->empty())
734                                                 removeFirstEqual(m_nonEmptyHeaps, heap);
735                                 }
736                         }
737
738                         m_opNdx++;
739                         return tcu::TestStatus::incomplete();
740                 }
741                 else
742                         return tcu::TestStatus::pass("Pass");
743         }
744
745 private:
746         de::Random                                                      m_rng;
747         size_t                                                          m_opNdx;
748
749         vector<de::SharedPtr<MemoryHeap> >      m_nonEmptyHeaps;
750         vector<de::SharedPtr<MemoryHeap> >      m_nonFullHeaps;
751
752         vector<MemoryObject*>                           m_mappedMemoryObjects;
753         vector<MemoryObject*>                           m_nonMappedMemoryObjects;
754         vector<MemoryMapping*>                          m_memoryMappings;
755 };
756
757 enum Op
758 {
759         OP_NONE = 0,
760
761         OP_FLUSH,
762         OP_SUB_FLUSH,
763         OP_SUB_FLUSH_SEPARATE,
764         OP_SUB_FLUSH_OVERLAPPING,
765
766         OP_INVALIDATE,
767         OP_SUB_INVALIDATE,
768         OP_SUB_INVALIDATE_SEPARATE,
769         OP_SUB_INVALIDATE_OVERLAPPING,
770
771         OP_REMAP,
772
773         OP_LAST
774 };
775
776 TestConfig subMappedConfig (VkDeviceSize                                allocationSize,
777                                                         const MemoryRange&                      mapping,
778                                                         Op                                                      op,
779                                                         deUint32                                        seed)
780 {
781         TestConfig config;
782
783         config.allocationSize   = allocationSize;
784         config.seed                             = seed;
785         config.mapping                  = mapping;
786         config.remap                    = false;
787
788         switch (op)
789         {
790                 case OP_NONE:
791                         return config;
792
793                 case OP_REMAP:
794                         config.remap = true;
795                         return config;
796
797                 case OP_FLUSH:
798                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(0, allocationSize));
799                         return config;
800
801                 case OP_SUB_FLUSH:
802                         DE_ASSERT(allocationSize / 4 > 0);
803
804                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(allocationSize / 4, allocationSize / 2));
805                         return config;
806
807                 case OP_SUB_FLUSH_SEPARATE:
808                         DE_ASSERT(allocationSize / 2 > 0);
809
810                         config.flushMappings.push_back(MemoryRange(allocationSize /  2, allocationSize - (allocationSize / 2)));
811                         config.flushMappings.push_back(MemoryRange(0, allocationSize / 2));
812
813                         return config;
814
815                 case OP_SUB_FLUSH_OVERLAPPING:
816                         DE_ASSERT((allocationSize / 3) > 0);
817
818                         config.flushMappings.push_back(MemoryRange(allocationSize /  3, allocationSize - (allocationSize / 2)));
819                         config.flushMappings.push_back(MemoryRange(0, (2 * allocationSize) / 3));
820
821                         return config;
822
823                 case OP_INVALIDATE:
824                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(0, allocationSize));
825                         return config;
826
827                 case OP_SUB_INVALIDATE:
828                         DE_ASSERT(allocationSize / 4 > 0);
829
830                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(allocationSize / 4, allocationSize / 2));
831                         return config;
832
833                 case OP_SUB_INVALIDATE_SEPARATE:
834                         DE_ASSERT(allocationSize / 2 > 0);
835
836                         config.invalidateMappings.push_back(MemoryRange(allocationSize /  2, allocationSize - (allocationSize / 2)));
837                         config.invalidateMappings.push_back(MemoryRange(0, allocationSize / 2));
838
839                         return config;
840
841                 case OP_SUB_INVALIDATE_OVERLAPPING:
842                         DE_ASSERT((allocationSize / 3) > 0);
843
844                         config.invalidateMappings.push_back(MemoryRange(allocationSize /  3, allocationSize - (allocationSize / 2)));
845                         config.invalidateMappings.push_back(MemoryRange(0, (2 * allocationSize) / 3));
846
847                         return config;
848
849                 default:
850                         DE_FATAL("Unknown Op");
851                         return TestConfig();
852         }
853 }
854
855 TestConfig fullMappedConfig (VkDeviceSize       allocationSize,
856                                                          Op                             op,
857                                                          deUint32               seed)
858 {
859         return subMappedConfig(allocationSize, MemoryRange(0, allocationSize), op, seed);
860 }
861
862 } // anonymous
863
864 tcu::TestCaseGroup* createMappingTests (tcu::TestContext& testCtx)
865 {
866         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "mapping", "Memory mapping tests."));
867
868         const VkDeviceSize allocationSizes[] =
869         {
870                 33, 257, 4087, 8095, 1*1024*1024 + 1
871         };
872
873         const VkDeviceSize offsets[] =
874         {
875                 0, 17, 129, 255, 1025, 32*1024+1
876         };
877
878         const VkDeviceSize sizes[] =
879         {
880                 31, 255, 1025, 4085, 1*1024*1024 - 1
881         };
882
883         const struct
884         {
885                 const Op                        op;
886                 const char* const       name;
887         } ops[] =
888         {
889                 { OP_NONE,                                              "simple"                                        },
890                 { OP_REMAP,                                             "remap"                                         },
891                 { OP_FLUSH,                                             "flush"                                         },
892                 { OP_SUB_FLUSH,                                 "subflush"                                      },
893                 { OP_SUB_FLUSH_SEPARATE,                "subflush_separate"                     },
894                 { OP_SUB_FLUSH_SEPARATE,                "subflush_overlapping"          },
895
896                 { OP_INVALIDATE,                                "invalidate"                            },
897                 { OP_SUB_INVALIDATE,                    "subinvalidate"                         },
898                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_separate"        },
899                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_overlapping"     }
900         };
901
902         // .full
903         {
904                 de::MovePtr<tcu::TestCaseGroup> fullGroup (new tcu::TestCaseGroup(testCtx, "full", "Map memory completely."));
905
906                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
907                 {
908                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
909                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
910
911                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
912                         {
913                                 const Op                        op              = ops[opNdx].op;
914                                 const char* const       name    = ops[opNdx].name;
915                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
916                                 const TestConfig        config  = fullMappedConfig(allocationSize, op, seed);
917
918                                 addFunctionCase(allocationSizeGroup.get(), name, name, testMemoryMapping, config);
919                         }
920
921                         fullGroup->addChild(allocationSizeGroup.release());
922                 }
923
924                 group->addChild(fullGroup.release());
925         }
926
927         // .sub
928         {
929                 de::MovePtr<tcu::TestCaseGroup> subGroup (new tcu::TestCaseGroup(testCtx, "sub", "Map part of the memory."));
930
931                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
932                 {
933                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
934                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
935
936                         for (size_t offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++)
937                         {
938                                 const VkDeviceSize                              offset                  = offsets[offsetNdx];
939
940                                 if (offset >= allocationSize)
941                                         continue;
942
943                                 de::MovePtr<tcu::TestCaseGroup> offsetGroup             (new tcu::TestCaseGroup(testCtx, ("offset_" + de::toString(offset)).c_str(), ""));
944
945                                 for (size_t sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); sizeNdx++)
946                                 {
947                                         const VkDeviceSize                              size            = sizes[sizeNdx];
948
949                                         if (offset + size > allocationSize)
950                                                 continue;
951
952                                         if (offset == 0 && size == allocationSize)
953                                                 continue;
954
955                                         de::MovePtr<tcu::TestCaseGroup> sizeGroup       (new tcu::TestCaseGroup(testCtx, ("size_" + de::toString(size)).c_str(), ""));
956
957                                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
958                                         {
959                                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
960                                                 const Op                        op              = ops[opNdx].op;
961                                                 const char* const       name    = ops[opNdx].name;
962                                                 const TestConfig        config  = subMappedConfig(allocationSize, MemoryRange(offset, size), op, seed);
963
964                                                 addFunctionCase(sizeGroup.get(), name, name, testMemoryMapping, config);
965                                         }
966
967                                         offsetGroup->addChild(sizeGroup.release());
968                                 }
969
970                                 allocationSizeGroup->addChild(offsetGroup.release());
971                         }
972
973                         subGroup->addChild(allocationSizeGroup.release());
974                 }
975
976                 group->addChild(subGroup.release());
977         }
978
979         // .random
980         {
981                 de::MovePtr<tcu::TestCaseGroup> randomGroup     (new tcu::TestCaseGroup(testCtx, "random", "Random memory mapping tests."));
982                 de::Random                                              rng                     (3927960301u);
983
984                 for (size_t ndx = 0; ndx < 100; ndx++)
985                 {
986                         const deUint32          seed    = rng.getUint32();
987                         const std::string       name    = de::toString(ndx);
988
989                         randomGroup->addChild(new InstanceFactory1<RandomMemoryMappingInstance, deUint32>(testCtx, tcu::NODETYPE_SELF_VALIDATE, de::toString(ndx), "Random case", seed));
990                 }
991
992                 group->addChild(randomGroup.release());
993         }
994
995         return group.release();
996 }
997
998 } // memory
999 } // vkt