We need to allocate memory before we can create a buffer view
[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(0, 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(0, 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/8 of each memory heap.
503         MAX_MEMORY_USAGE_DIV = 8
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() % ((m_heap.size / MAX_MEMORY_USAGE_DIV) - m_usage - 1));
543                 const deUint32                  type    = rng.choose<deUint32>(m_memoryTypes.begin(), m_memoryTypes.end());
544                 MemoryObject* const             object  = new MemoryObject(vkd, device, size, type);
545
546                 m_usage += size;
547                 m_objects.push_back(object);
548
549                 return object;
550         }
551
552         MemoryObject*                                           getRandomObject (de::Random& rng) const
553         {
554                 return rng.choose<MemoryObject*>(m_objects.begin(), m_objects.end());
555         }
556
557         void                                                            free                    (MemoryObject* object)
558         {
559                 removeFirstEqual(m_objects, object);
560                 m_usage -= object->getSize();
561                 delete object;
562         }
563
564 private:
565         VkMemoryHeap                    m_heap;
566         vector<deUint32>                m_memoryTypes;
567
568         VkDeviceSize                    m_usage;
569         vector<MemoryObject*>   m_objects;
570 };
571
572 class RandomMemoryMappingInstance : public TestInstance
573 {
574 public:
575         RandomMemoryMappingInstance (Context& context, deUint32 seed)
576                 : TestInstance  (context)
577                 , m_rng                 (seed)
578                 , m_opNdx               (0)
579         {
580                 const VkPhysicalDevice                                  physicalDevice          = context.getPhysicalDevice();
581                 const InstanceInterface&                                vki                                     = context.getInstanceInterface();
582                 const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
583
584                 // Initialize heaps
585                 {
586                         vector<vector<deUint32> >       memoryTypes     (memoryProperties.memoryHeapCount);
587
588                         for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
589                         {
590                                 if (memoryProperties.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
591                                         memoryTypes[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].push_back(memoryTypeNdx);
592                         }
593
594                         for (deUint32 heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; heapIndex++)
595                         {
596                                 const VkMemoryHeap      heapInfo        = memoryProperties.memoryHeaps[heapIndex];
597
598                                 if (!memoryTypes[heapIndex].empty())
599                                 {
600                                         const de::SharedPtr<MemoryHeap> heap    (new MemoryHeap(heapInfo, memoryTypes[heapIndex]));
601
602                                         if (!heap->full())
603                                                 m_nonFullHeaps.push_back(heap);
604                                 }
605                         }
606                 }
607         }
608
609         ~RandomMemoryMappingInstance (void)
610         {
611         }
612
613         tcu::TestStatus iterate (void)
614         {
615                 const size_t                    opCount                                         = 100;
616                 const float                             memoryOpProbability                     = 0.5f;         // 0.50
617                 const float                             flushInvalidateProbability      = 0.4f;         // 0.20
618                 const float                             mapProbability                          = 0.50f;        // 0.15
619                 const float                             unmapProbability                        = 0.25f;        // 0.075
620
621                 const float                             allocProbability                        = 0.75f; // Versun free
622
623                 const VkDevice                  device                                          = m_context.getDevice();
624                 const DeviceInterface&  vkd                                                     = m_context.getDeviceInterface();
625
626                 if (m_opNdx < opCount)
627                 {
628                         if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
629                         {
630                                 // Perform operations on mapped memory
631                                 MemoryMapping* const    mapping = m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
632
633                                 enum Op
634                                 {
635                                         OP_READ = 0,
636                                         OP_WRITE,
637                                         OP_MODIFY,
638                                         OP_LAST
639                                 };
640
641                                 const Op op = (Op)(m_rng.getUint32() % OP_LAST);
642
643                                 switch (op)
644                                 {
645                                         case OP_READ:
646                                                 mapping->randomRead(m_rng);
647                                                 break;
648
649                                         case OP_WRITE:
650                                                 mapping->randomWrite(m_rng);
651                                                 break;
652
653                                         case OP_MODIFY:
654                                                 mapping->randomModify(m_rng);
655                                                 break;
656
657                                         default:
658                                                 DE_FATAL("Invalid operation");
659                                 }
660                         }
661                         else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
662                         {
663                                 MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
664
665                                 if (m_rng.getBool())
666                                         object->randomFlush(vkd, device, m_rng);
667                                 else
668                                         object->randomInvalidate(vkd, device, m_rng);
669                         }
670                         else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
671                         {
672                                 // Unmap memory object
673                                 MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
674
675                                 // Remove mapping
676                                 removeFirstEqual(m_memoryMappings, object->getMapping());
677
678                                 object->unmap();
679                                 removeFirstEqual(m_mappedMemoryObjects, object);
680                                 m_nonMappedMemoryObjects.push_back(object);
681                         }
682                         else if (!m_nonMappedMemoryObjects.empty() && m_rng.getFloat() < mapProbability)
683                         {
684                                 // Map memory object
685                                 MemoryObject* const             object  = m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
686                                 MemoryMapping*                  mapping = object->mapRandom(vkd, device, m_rng);
687
688                                 m_memoryMappings.push_back(mapping);
689                                 m_mappedMemoryObjects.push_back(object);
690                                 removeFirstEqual(m_nonMappedMemoryObjects, object);
691                         }
692                         else
693                         {
694                                 if (!m_nonFullHeaps.empty() && (m_nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
695                                 {
696                                         // Allocate more memory objects
697                                         de::SharedPtr<MemoryHeap> const heap = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonFullHeaps.begin(), m_nonFullHeaps.end());
698
699                                         if (heap->empty())
700                                                 m_nonEmptyHeaps.push_back(heap);
701
702                                         {
703                                                 MemoryObject* const     object = heap->allocateRandom(vkd, device, m_rng);
704
705                                                 if (heap->full())
706                                                         removeFirstEqual(m_nonFullHeaps, heap);
707
708                                                 m_nonMappedMemoryObjects.push_back(object);
709                                         }
710                                 }
711                                 else
712                                 {
713                                         // Free memory objects
714                                         de::SharedPtr<MemoryHeap> const         heap    = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonEmptyHeaps.begin(), m_nonEmptyHeaps.end());
715                                         MemoryObject* const                                     object  = heap->getRandomObject(m_rng);
716
717                                         // Remove mapping
718                                         if (object->getMapping())
719                                                 removeFirstEqual(m_memoryMappings, object->getMapping());
720
721                                         removeFirstEqual(m_mappedMemoryObjects, object);
722                                         removeFirstEqual(m_nonMappedMemoryObjects, object);
723
724                                         if (heap->full())
725                                                 m_nonFullHeaps.push_back(heap);
726
727                                         heap->free(object);
728
729                                         if (heap->empty())
730                                                 removeFirstEqual(m_nonEmptyHeaps, heap);
731                                 }
732                         }
733
734                         m_opNdx++;
735                         return tcu::TestStatus::incomplete();
736                 }
737                 else
738                         return tcu::TestStatus::pass("Pass");
739         }
740
741 private:
742         de::Random                                                      m_rng;
743         size_t                                                          m_opNdx;
744
745         vector<de::SharedPtr<MemoryHeap> >      m_nonEmptyHeaps;
746         vector<de::SharedPtr<MemoryHeap> >      m_nonFullHeaps;
747
748         vector<MemoryObject*>                           m_mappedMemoryObjects;
749         vector<MemoryObject*>                           m_nonMappedMemoryObjects;
750         vector<MemoryMapping*>                          m_memoryMappings;
751 };
752
753 enum Op
754 {
755         OP_NONE = 0,
756
757         OP_FLUSH,
758         OP_SUB_FLUSH,
759         OP_SUB_FLUSH_SEPARATE,
760         OP_SUB_FLUSH_OVERLAPPING,
761
762         OP_INVALIDATE,
763         OP_SUB_INVALIDATE,
764         OP_SUB_INVALIDATE_SEPARATE,
765         OP_SUB_INVALIDATE_OVERLAPPING,
766
767         OP_REMAP,
768
769         OP_LAST
770 };
771
772 TestConfig subMappedConfig (VkDeviceSize                                allocationSize,
773                                                         const MemoryRange&                      mapping,
774                                                         Op                                                      op,
775                                                         deUint32                                        seed)
776 {
777         TestConfig config;
778
779         config.allocationSize   = allocationSize;
780         config.seed                             = seed;
781         config.mapping                  = mapping;
782         config.remap                    = false;
783
784         switch (op)
785         {
786                 case OP_NONE:
787                         return config;
788
789                 case OP_REMAP:
790                         config.remap = true;
791                         return config;
792
793                 case OP_FLUSH:
794                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(0, allocationSize));
795                         return config;
796
797                 case OP_SUB_FLUSH:
798                         DE_ASSERT(allocationSize / 4 > 0);
799
800                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(allocationSize / 4, allocationSize / 2));
801                         return config;
802
803                 case OP_SUB_FLUSH_SEPARATE:
804                         DE_ASSERT(allocationSize / 2 > 0);
805
806                         config.flushMappings.push_back(MemoryRange(allocationSize /  2, allocationSize - (allocationSize / 2)));
807                         config.flushMappings.push_back(MemoryRange(0, allocationSize / 2));
808
809                         return config;
810
811                 case OP_SUB_FLUSH_OVERLAPPING:
812                         DE_ASSERT((allocationSize / 3) > 0);
813
814                         config.flushMappings.push_back(MemoryRange(allocationSize /  3, allocationSize - (allocationSize / 2)));
815                         config.flushMappings.push_back(MemoryRange(0, (2 * allocationSize) / 3));
816
817                         return config;
818
819                 case OP_INVALIDATE:
820                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(0, allocationSize));
821                         return config;
822
823                 case OP_SUB_INVALIDATE:
824                         DE_ASSERT(allocationSize / 4 > 0);
825
826                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(allocationSize / 4, allocationSize / 2));
827                         return config;
828
829                 case OP_SUB_INVALIDATE_SEPARATE:
830                         DE_ASSERT(allocationSize / 2 > 0);
831
832                         config.invalidateMappings.push_back(MemoryRange(allocationSize /  2, allocationSize - (allocationSize / 2)));
833                         config.invalidateMappings.push_back(MemoryRange(0, allocationSize / 2));
834
835                         return config;
836
837                 case OP_SUB_INVALIDATE_OVERLAPPING:
838                         DE_ASSERT((allocationSize / 3) > 0);
839
840                         config.invalidateMappings.push_back(MemoryRange(allocationSize /  3, allocationSize - (allocationSize / 2)));
841                         config.invalidateMappings.push_back(MemoryRange(0, (2 * allocationSize) / 3));
842
843                         return config;
844
845                 default:
846                         DE_FATAL("Unknown Op");
847                         return TestConfig();
848         }
849 }
850
851 TestConfig fullMappedConfig (VkDeviceSize       allocationSize,
852                                                          Op                             op,
853                                                          deUint32               seed)
854 {
855         return subMappedConfig(allocationSize, MemoryRange(0, allocationSize), op, seed);
856 }
857
858 } // anonymous
859
860 tcu::TestCaseGroup* createMappingTests (tcu::TestContext& testCtx)
861 {
862         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "mapping", "Memory mapping tests."));
863
864         const VkDeviceSize allocationSizes[] =
865         {
866                 33, 257, 4087, 8095, 1*1024*1024 + 1
867         };
868
869         const VkDeviceSize offsets[] =
870         {
871                 0, 17, 129, 255, 1025, 32*1024+1
872         };
873
874         const VkDeviceSize sizes[] =
875         {
876                 31, 255, 1025, 4085, 1*1024*1024 - 1
877         };
878
879         const struct
880         {
881                 const Op                        op;
882                 const char* const       name;
883         } ops[] =
884         {
885                 { OP_NONE,                                              "simple"                                        },
886                 { OP_REMAP,                                             "remap"                                         },
887                 { OP_FLUSH,                                             "flush"                                         },
888                 { OP_SUB_FLUSH,                                 "subflush"                                      },
889                 { OP_SUB_FLUSH_SEPARATE,                "subflush_separate"                     },
890                 { OP_SUB_FLUSH_SEPARATE,                "subflush_overlapping"          },
891
892                 { OP_INVALIDATE,                                "invalidate"                            },
893                 { OP_SUB_INVALIDATE,                    "subinvalidate"                         },
894                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_separate"        },
895                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_overlapping"     }
896         };
897
898         // .full
899         {
900                 de::MovePtr<tcu::TestCaseGroup> fullGroup (new tcu::TestCaseGroup(testCtx, "full", "Map memory completely."));
901
902                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
903                 {
904                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
905                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
906
907                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
908                         {
909                                 const Op                        op              = ops[opNdx].op;
910                                 const char* const       name    = ops[opNdx].name;
911                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
912                                 const TestConfig        config  = fullMappedConfig(allocationSize, op, seed);
913
914                                 addFunctionCase(allocationSizeGroup.get(), name, name, testMemoryMapping, config);
915                         }
916
917                         fullGroup->addChild(allocationSizeGroup.release());
918                 }
919
920                 group->addChild(fullGroup.release());
921         }
922
923         // .sub
924         {
925                 de::MovePtr<tcu::TestCaseGroup> subGroup (new tcu::TestCaseGroup(testCtx, "sub", "Map part of the memory."));
926
927                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
928                 {
929                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
930                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
931
932                         for (size_t offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++)
933                         {
934                                 const VkDeviceSize                              offset                  = offsets[offsetNdx];
935
936                                 if (offset >= allocationSize)
937                                         continue;
938
939                                 de::MovePtr<tcu::TestCaseGroup> offsetGroup             (new tcu::TestCaseGroup(testCtx, ("offset_" + de::toString(offset)).c_str(), ""));
940
941                                 for (size_t sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); sizeNdx++)
942                                 {
943                                         const VkDeviceSize                              size            = sizes[sizeNdx];
944
945                                         if (offset + size > allocationSize)
946                                                 continue;
947
948                                         if (offset == 0 && size == allocationSize)
949                                                 continue;
950
951                                         de::MovePtr<tcu::TestCaseGroup> sizeGroup       (new tcu::TestCaseGroup(testCtx, ("size_" + de::toString(size)).c_str(), ""));
952
953                                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
954                                         {
955                                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
956                                                 const Op                        op              = ops[opNdx].op;
957                                                 const char* const       name    = ops[opNdx].name;
958                                                 const TestConfig        config  = subMappedConfig(allocationSize, MemoryRange(offset, size), op, seed);
959
960                                                 addFunctionCase(sizeGroup.get(), name, name, testMemoryMapping, config);
961                                         }
962
963                                         offsetGroup->addChild(sizeGroup.release());
964                                 }
965
966                                 allocationSizeGroup->addChild(offsetGroup.release());
967                         }
968
969                         subGroup->addChild(allocationSizeGroup.release());
970                 }
971
972                 group->addChild(subGroup.release());
973         }
974
975         // .random
976         {
977                 de::MovePtr<tcu::TestCaseGroup> randomGroup     (new tcu::TestCaseGroup(testCtx, "random", "Random memory mapping tests."));
978                 de::Random                                              rng                     (3927960301u);
979
980                 for (size_t ndx = 0; ndx < 100; ndx++)
981                 {
982                         const deUint32          seed    = rng.getUint32();
983                         const std::string       name    = de::toString(ndx);
984
985                         randomGroup->addChild(new InstanceFactory1<RandomMemoryMappingInstance, deUint32>(testCtx, tcu::NODETYPE_SELF_VALIDATE, de::toString(ndx), "Random case", seed));
986                 }
987
988                 group->addChild(randomGroup.release());
989         }
990
991         return group.release();
992 }
993
994 } // memory
995 } // vkt