f9470c2292805a07e9feff3ccdf730e3e1ad9d70
[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  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Simple memory mapping tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktMemoryMappingTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27
28 #include "tcuMaybe.hpp"
29 #include "tcuResultCollector.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuPlatform.hpp"
32
33 #include "vkDeviceUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkStrUtil.hpp"
39 #include "vkAllocationCallbackUtil.hpp"
40
41 #include "deRandom.hpp"
42 #include "deSharedPtr.hpp"
43 #include "deStringUtil.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deSTLUtil.hpp"
46
47 #include <string>
48 #include <vector>
49 #include <algorithm>
50
51 using tcu::Maybe;
52 using tcu::TestLog;
53
54 using de::SharedPtr;
55
56 using std::string;
57 using std::vector;
58
59 using namespace vk;
60
61 namespace vkt
62 {
63 namespace memory
64 {
65 namespace
66 {
67 enum
68 {
69         REFERENCE_BYTES_PER_BYTE = 2
70 };
71
72 size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device)
73 {
74         AllocationCallbackRecorder      callbackRecorder        (getSystemAllocator());
75
76         {
77                 // 1 B allocation from memory type 0
78                 const VkMemoryAllocateInfo      allocInfo       =
79                 {
80                         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
81                         DE_NULL,
82                         1u,
83                         0u,
84                 };
85                 const Unique<VkDeviceMemory>                    memory                  (allocateMemory(vk, device, &allocInfo));
86                 AllocationCallbackValidationResults             validateRes;
87
88                 validateAllocationCallbacks(callbackRecorder, &validateRes);
89
90                 TCU_CHECK(validateRes.violations.empty());
91
92                 return getLiveSystemAllocationTotal(validateRes)
93                            + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead
94         }
95 }
96
97 Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, VkDeviceSize pAllocInfo_allocationSize, deUint32 pAllocInfo_memoryTypeIndex)
98 {
99         const VkMemoryAllocateInfo pAllocInfo =
100         {
101                 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
102                 DE_NULL,
103                 pAllocInfo_allocationSize,
104                 pAllocInfo_memoryTypeIndex,
105         };
106         return allocateMemory(vk, device, &pAllocInfo);
107 }
108
109 struct MemoryRange
110 {
111         MemoryRange (VkDeviceSize offset_ = ~(VkDeviceSize)0, VkDeviceSize size_ = ~(VkDeviceSize)0)
112                 : offset        (offset_)
113                 , size          (size_)
114         {
115         }
116
117         VkDeviceSize    offset;
118         VkDeviceSize    size;
119 };
120
121 struct TestConfig
122 {
123         TestConfig (void)
124                 : allocationSize        (~(VkDeviceSize)0)
125         {
126         }
127
128         VkDeviceSize            allocationSize;
129         deUint32                        seed;
130
131         MemoryRange                     mapping;
132         vector<MemoryRange>     flushMappings;
133         vector<MemoryRange>     invalidateMappings;
134         bool                            remap;
135 };
136
137 bool compareAndLogBuffer (TestLog& log, size_t size, const deUint8* result, const deUint8* reference)
138 {
139         size_t  failedBytes     = 0;
140         size_t  firstFailed     = (size_t)-1;
141
142         for (size_t ndx = 0; ndx < size; ndx++)
143         {
144                 if (result[ndx] != reference[ndx])
145                 {
146                         failedBytes++;
147
148                         if (firstFailed == (size_t)-1)
149                                 firstFailed = ndx;
150                 }
151         }
152
153         if (failedBytes > 0)
154         {
155                 log << TestLog::Message << "Comparison failed. Failed bytes " << failedBytes << ". First failed at offset " << firstFailed << "." << TestLog::EndMessage;
156
157                 std::ostringstream      expectedValues;
158                 std::ostringstream      resultValues;
159
160                 for (size_t ndx = firstFailed; ndx < firstFailed + 10 && ndx < size; ndx++)
161                 {
162                         if (ndx != firstFailed)
163                         {
164                                 expectedValues << ", ";
165                                 resultValues << ", ";
166                         }
167
168                         expectedValues << reference[ndx];
169                         resultValues << result[ndx];
170                 }
171
172                 if (firstFailed + 10 < size)
173                 {
174                         expectedValues << "...";
175                         resultValues << "...";
176                 }
177
178                 log << TestLog::Message << "Expected values at offset: " << firstFailed << ", " << expectedValues.str() << TestLog::EndMessage;
179                 log << TestLog::Message << "Result values at offset: " << firstFailed << ", " << resultValues.str() << TestLog::EndMessage;
180
181                 return false;
182         }
183         else
184                 return true;
185 }
186
187 tcu::TestStatus testMemoryMapping (Context& context, const TestConfig config)
188 {
189         TestLog&                                                                log                                     = context.getTestContext().getLog();
190         tcu::ResultCollector                                    result                          (log);
191         const VkPhysicalDevice                                  physicalDevice          = context.getPhysicalDevice();
192         const VkDevice                                                  device                          = context.getDevice();
193         const InstanceInterface&                                vki                                     = context.getInstanceInterface();
194         const DeviceInterface&                                  vkd                                     = context.getDeviceInterface();
195         const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
196         // \todo [2016-05-27 misojarvi] Remove once drivers start reporting correctly nonCoherentAtomSize that is at least 1.
197         const VkDeviceSize                                              nonCoherentAtomSize     = context.getDeviceProperties().limits.nonCoherentAtomSize != 0
198                                                                                                                                 ? context.getDeviceProperties().limits.nonCoherentAtomSize
199                                                                                                                                 : 1;
200
201         {
202                 const tcu::ScopedLogSection     section (log, "TestCaseInfo", "TestCaseInfo");
203
204                 log << TestLog::Message << "Seed: " << config.seed << TestLog::EndMessage;
205                 log << TestLog::Message << "Allocation size: " << config.allocationSize << " * atom" <<  TestLog::EndMessage;
206                 log << TestLog::Message << "Mapping, offset: " << config.mapping.offset << " * atom, size: " << config.mapping.size << " * atom" << TestLog::EndMessage;
207
208                 if (!config.flushMappings.empty())
209                 {
210                         log << TestLog::Message << "Invalidating following ranges:" << TestLog::EndMessage;
211
212                         for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
213                                 log << TestLog::Message << "\tOffset: " << config.flushMappings[ndx].offset << " * atom, Size: " << config.flushMappings[ndx].size << " * atom" << TestLog::EndMessage;
214                 }
215
216                 if (config.remap)
217                         log << TestLog::Message << "Remapping memory between flush and invalidation." << TestLog::EndMessage;
218
219                 if (!config.invalidateMappings.empty())
220                 {
221                         log << TestLog::Message << "Flushing following ranges:" << TestLog::EndMessage;
222
223                         for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
224                                 log << TestLog::Message << "\tOffset: " << config.invalidateMappings[ndx].offset << " * atom, Size: " << config.invalidateMappings[ndx].size << " * atom" << TestLog::EndMessage;
225                 }
226         }
227
228         for (deUint32 memoryTypeIndex = 0; memoryTypeIndex < memoryProperties.memoryTypeCount; memoryTypeIndex++)
229         {
230                 try
231                 {
232                         const tcu::ScopedLogSection             section         (log, "MemoryType" + de::toString(memoryTypeIndex), "MemoryType" + de::toString(memoryTypeIndex));
233                         const VkMemoryType&                             memoryType      = memoryProperties.memoryTypes[memoryTypeIndex];
234                         const VkMemoryHeap&                             memoryHeap      = memoryProperties.memoryHeaps[memoryType.heapIndex];
235                         const VkDeviceSize                              atomSize        = (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0
236                                                                                                                 ? 1
237                                                                                                                 : nonCoherentAtomSize;
238
239                         log << TestLog::Message << "MemoryType: " << memoryType << TestLog::EndMessage;
240                         log << TestLog::Message << "MemoryHeap: " << memoryHeap << TestLog::EndMessage;
241                         log << TestLog::Message << "AtomSize: " << atomSize << TestLog::EndMessage;
242                         log << TestLog::Message << "AllocationSize: " << config.allocationSize * atomSize <<  TestLog::EndMessage;
243                         log << TestLog::Message << "Mapping, offset: " << config.mapping.offset * atomSize << ", size: " << config.mapping.size * atomSize << TestLog::EndMessage;
244
245                         if (!config.flushMappings.empty())
246                         {
247                                 log << TestLog::Message << "Invalidating following ranges:" << TestLog::EndMessage;
248
249                                 for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
250                                         log << TestLog::Message << "\tOffset: " << config.flushMappings[ndx].offset * atomSize << ", Size: " << config.flushMappings[ndx].size * atomSize << TestLog::EndMessage;
251                         }
252
253                         if (!config.invalidateMappings.empty())
254                         {
255                                 log << TestLog::Message << "Flushing following ranges:" << TestLog::EndMessage;
256
257                                 for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
258                                         log << TestLog::Message << "\tOffset: " << config.invalidateMappings[ndx].offset * atomSize << ", Size: " << config.invalidateMappings[ndx].size * atomSize << TestLog::EndMessage;
259                         }
260
261                         if ((memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
262                         {
263                                 log << TestLog::Message << "Memory type doesn't support mapping." << TestLog::EndMessage;
264                         }
265                         else if (memoryHeap.size <= 4 * atomSize * config.allocationSize)
266                         {
267                                 log << TestLog::Message << "Memory types heap is too small." << TestLog::EndMessage;
268                         }
269                         else
270                         {
271                                 const Unique<VkDeviceMemory>    memory                          (allocMemory(vkd, device, config.allocationSize * atomSize, memoryTypeIndex));
272                                 de::Random                                              rng                                     (config.seed);
273                                 vector<deUint8>                                 reference                       ((size_t)(config.allocationSize * atomSize));
274                                 deUint8*                                                mapping                         = DE_NULL;
275
276                                 {
277                                         void* ptr;
278                                         VK_CHECK(vkd.mapMemory(device, *memory, config.mapping.offset * atomSize, config.mapping.size * atomSize, 0u, &ptr));
279                                         TCU_CHECK(ptr);
280
281                                         mapping = (deUint8*)ptr;
282                                 }
283
284                                 for (VkDeviceSize ndx = 0; ndx < config.mapping.size * atomSize; ndx++)
285                                 {
286                                         const deUint8 val = rng.getUint8();
287
288                                         mapping[ndx]                                                                                            = val;
289                                         reference[(size_t)(config.mapping.offset * atomSize + ndx)]     = val;
290                                 }
291
292                                 if (!config.flushMappings.empty())
293                                 {
294                                         vector<VkMappedMemoryRange> ranges;
295
296                                         for (size_t ndx = 0; ndx < config.flushMappings.size(); ndx++)
297                                         {
298                                                 const VkMappedMemoryRange range =
299                                                 {
300                                                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
301                                                         DE_NULL,
302
303                                                         *memory,
304                                                         config.flushMappings[ndx].offset * atomSize,
305                                                         config.flushMappings[ndx].size * atomSize
306                                                 };
307
308                                                 ranges.push_back(range);
309                                         }
310
311                                         VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), &ranges[0]));
312                                 }
313
314                                 if (config.remap)
315                                 {
316                                         void* ptr;
317                                         vkd.unmapMemory(device, *memory);
318                                         VK_CHECK(vkd.mapMemory(device, *memory, config.mapping.offset * atomSize, config.mapping.size * atomSize, 0u, &ptr));
319                                         TCU_CHECK(ptr);
320
321                                         mapping = (deUint8*)ptr;
322                                 }
323
324                                 if (!config.invalidateMappings.empty())
325                                 {
326                                         vector<VkMappedMemoryRange> ranges;
327
328                                         for (size_t ndx = 0; ndx < config.invalidateMappings.size(); ndx++)
329                                         {
330                                                 const VkMappedMemoryRange range =
331                                                 {
332                                                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
333                                                         DE_NULL,
334
335                                                         *memory,
336                                                         config.invalidateMappings[ndx].offset * atomSize,
337                                                         config.invalidateMappings[ndx].size * atomSize
338                                                 };
339
340                                                 ranges.push_back(range);
341                                         }
342
343                                         VK_CHECK(vkd.invalidateMappedMemoryRanges(device, (deUint32)ranges.size(), &ranges[0]));
344                                 }
345
346                                 if (!compareAndLogBuffer(log, (size_t)(config.mapping.size * atomSize), mapping, &reference[(size_t)(config.mapping.offset * atomSize)]))
347                                         result.fail("Unexpected values read from mapped memory.");
348
349                                 vkd.unmapMemory(device, *memory);
350                         }
351                 }
352                 catch (const tcu::TestError& error)
353                 {
354                         result.fail(error.getMessage());
355                 }
356         }
357
358         return tcu::TestStatus(result.getResult(), result.getMessage());
359 }
360
361 class MemoryMapping
362 {
363 public:
364                                                 MemoryMapping   (const MemoryRange&     range,
365                                                                                  void*                          ptr,
366                                                                                  deUint16*                      refPtr);
367
368         void                            randomRead              (de::Random& rng);
369         void                            randomWrite             (de::Random& rng);
370         void                            randomModify    (de::Random& rng);
371
372         const MemoryRange&      getRange                (void) const { return m_range; }
373
374 private:
375         MemoryRange     m_range;
376         void*           m_ptr;
377         deUint16*       m_refPtr;
378 };
379
380 MemoryMapping::MemoryMapping (const MemoryRange&        range,
381                                                           void*                                 ptr,
382                                                           deUint16*                             refPtr)
383         : m_range       (range)
384         , m_ptr         (ptr)
385         , m_refPtr      (refPtr)
386 {
387         DE_ASSERT(range.size > 0);
388 }
389
390 void MemoryMapping::randomRead (de::Random& rng)
391 {
392         const size_t count = (size_t)rng.getInt(0, 100);
393
394         for (size_t ndx = 0; ndx < count; ndx++)
395         {
396                 const size_t    pos     = (size_t)(rng.getUint64() % (deUint64)m_range.size);
397                 const deUint8   val     = ((deUint8*) m_ptr)[pos];
398
399                 if (m_refPtr[pos] < 256)
400                         TCU_CHECK((deUint16)val == m_refPtr[pos]);
401                 else
402                         m_refPtr[pos] = (deUint16)val;
403         }
404 }
405
406 void MemoryMapping::randomWrite (de::Random& rng)
407 {
408         const size_t count = (size_t)rng.getInt(0, 100);
409
410         for (size_t ndx = 0; ndx < count; ndx++)
411         {
412                 const size_t    pos     = (size_t)(rng.getUint64() % (deUint64)m_range.size);
413                 const deUint8   val     = rng.getUint8();
414
415                 ((deUint8*)m_ptr)[pos]  = val;
416                 m_refPtr[pos]                   = (deUint16)val;
417         }
418 }
419
420 void MemoryMapping::randomModify (de::Random& rng)
421 {
422         const size_t count = (size_t)rng.getInt(0, 100);
423
424         for (size_t ndx = 0; ndx < count; ndx++)
425         {
426                 const size_t    pos             = (size_t)(rng.getUint64() % (deUint64)m_range.size);
427                 const deUint8   val             = ((deUint8*)m_ptr)[pos];
428                 const deUint8   mask    = rng.getUint8();
429
430                 if (m_refPtr[pos] < 256)
431                         TCU_CHECK((deUint16)val == m_refPtr[pos]);
432
433                 ((deUint8*)m_ptr)[pos]  = val ^ mask;
434                 m_refPtr[pos]                   = (deUint16)(val ^ mask);
435         }
436 }
437
438 void randomRanges (de::Random& rng, vector<VkMappedMemoryRange>& ranges, size_t count, VkDeviceMemory memory, VkDeviceSize minOffset, VkDeviceSize maxSize)
439 {
440         ranges.resize(count);
441
442         for (size_t rangeNdx = 0; rangeNdx < count; rangeNdx++)
443         {
444                 const VkDeviceSize      size    = (maxSize > 1 ? (VkDeviceSize)(1 + (rng.getUint64() % (deUint64)(maxSize - 1))) : 1);
445                 const VkDeviceSize      offset  = minOffset + (VkDeviceSize)(rng.getUint64() % (deUint64)(maxSize - size + 1));
446
447                 const VkMappedMemoryRange range =
448                 {
449                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
450                         DE_NULL,
451
452                         memory,
453                         offset,
454                         size
455                 };
456                 ranges[rangeNdx] = range;
457         }
458 }
459
460 class MemoryObject
461 {
462 public:
463                                                         MemoryObject            (const DeviceInterface&         vkd,
464                                                                                                  VkDevice                                       device,
465                                                                                                  VkDeviceSize                           size,
466                                                                                                  deUint32                                       memoryTypeIndex);
467
468                                                         ~MemoryObject           (void);
469
470         MemoryMapping*                  mapRandom                       (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
471         void                                    unmap                           (void);
472
473         void                                    randomFlush                     (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
474         void                                    randomInvalidate        (const DeviceInterface& vkd, VkDevice device, de::Random& rng);
475
476         VkDeviceSize                    getSize                         (void) const { return m_size; }
477         MemoryMapping*                  getMapping                      (void) { return m_mapping; }
478
479 private:
480         const DeviceInterface&  m_vkd;
481         VkDevice                                m_device;
482
483         deUint32                                m_memoryTypeIndex;
484         VkDeviceSize                    m_size;
485
486         Move<VkDeviceMemory>    m_memory;
487
488         MemoryMapping*                  m_mapping;
489         vector<deUint16>                m_reference;
490 };
491
492 MemoryObject::MemoryObject (const DeviceInterface&              vkd,
493                                                         VkDevice                                        device,
494                                                         VkDeviceSize                            size,
495                                                         deUint32                                        memoryTypeIndex)
496         : m_vkd                         (vkd)
497         , m_device                      (device)
498         , m_memoryTypeIndex     (memoryTypeIndex)
499         , m_size                        (size)
500         , m_mapping                     (DE_NULL)
501 {
502         m_memory = allocMemory(m_vkd, m_device, m_size, m_memoryTypeIndex);
503         m_reference.resize((size_t)m_size, 0xFFFFu);
504 }
505
506 MemoryObject::~MemoryObject (void)
507 {
508         delete m_mapping;
509 }
510
511 MemoryMapping* MemoryObject::mapRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
512 {
513         const VkDeviceSize      size    = (m_size > 1 ? (VkDeviceSize)(1 + (rng.getUint64() % (deUint64)(m_size - 1))) : 1);
514         const VkDeviceSize      offset  = (VkDeviceSize)(rng.getUint64() % (deUint64)(m_size - size + 1));
515         void*                           ptr;
516
517         DE_ASSERT(!m_mapping);
518
519         VK_CHECK(vkd.mapMemory(device, *m_memory, offset, size, 0u, &ptr));
520         TCU_CHECK(ptr);
521         m_mapping = new MemoryMapping(MemoryRange(offset, size), ptr, &(m_reference[(size_t)offset]));
522
523         return m_mapping;
524 }
525
526 void MemoryObject::unmap (void)
527 {
528         m_vkd.unmapMemory(m_device, *m_memory);
529
530         delete m_mapping;
531         m_mapping = DE_NULL;
532 }
533
534 void MemoryObject::randomFlush (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
535 {
536         const size_t                            rangeCount      = (size_t)rng.getInt(1, 10);
537         vector<VkMappedMemoryRange>     ranges          (rangeCount);
538
539         randomRanges(rng, ranges, rangeCount, *m_memory, m_mapping->getRange().offset, m_mapping->getRange().size);
540
541         VK_CHECK(vkd.flushMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
542 }
543
544 void MemoryObject::randomInvalidate (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
545 {
546         const size_t                            rangeCount      = (size_t)rng.getInt(1, 10);
547         vector<VkMappedMemoryRange>     ranges          (rangeCount);
548
549         randomRanges(rng, ranges, rangeCount, *m_memory, m_mapping->getRange().offset, m_mapping->getRange().size);
550
551         VK_CHECK(vkd.invalidateMappedMemoryRanges(device, (deUint32)ranges.size(), ranges.empty() ? DE_NULL : &ranges[0]));
552 }
553
554 enum
555 {
556         // Use only 1/2 of each memory heap.
557         MAX_MEMORY_USAGE_DIV = 2
558 };
559
560 template<typename T>
561 void removeFirstEqual (vector<T>& vec, const T& val)
562 {
563         for (size_t ndx = 0; ndx < vec.size(); ndx++)
564         {
565                 if (vec[ndx] == val)
566                 {
567                         vec[ndx] = vec.back();
568                         vec.pop_back();
569                         return;
570                 }
571         }
572 }
573
574 enum MemoryClass
575 {
576         MEMORY_CLASS_SYSTEM = 0,
577         MEMORY_CLASS_DEVICE,
578
579         MEMORY_CLASS_LAST
580 };
581
582 // \todo [2016-04-20 pyry] Consider estimating memory fragmentation
583 class TotalMemoryTracker
584 {
585 public:
586                                         TotalMemoryTracker      (void)
587         {
588                 std::fill(DE_ARRAY_BEGIN(m_usage), DE_ARRAY_END(m_usage), 0);
589         }
590
591         void                    allocate                        (MemoryClass memClass, VkDeviceSize size)
592         {
593                 m_usage[memClass] += size;
594         }
595
596         void                    free                            (MemoryClass memClass, VkDeviceSize size)
597         {
598                 DE_ASSERT(size <= m_usage[memClass]);
599                 m_usage[memClass] -= size;
600         }
601
602         VkDeviceSize    getUsage                        (MemoryClass memClass) const
603         {
604                 return m_usage[memClass];
605         }
606
607         VkDeviceSize    getTotalUsage           (void) const
608         {
609                 VkDeviceSize total = 0;
610                 for (int ndx = 0; ndx < MEMORY_CLASS_LAST; ++ndx)
611                         total += getUsage((MemoryClass)ndx);
612                 return total;
613         }
614
615 private:
616         VkDeviceSize    m_usage[MEMORY_CLASS_LAST];
617 };
618
619 class MemoryHeap
620 {
621 public:
622         MemoryHeap (const VkMemoryHeap&                 heap,
623                                 const vector<deUint32>&         memoryTypes,
624                                 const PlatformMemoryLimits&     memoryLimits,
625                                 TotalMemoryTracker&                     totalMemTracker)
626                 : m_heap                        (heap)
627                 , m_memoryTypes         (memoryTypes)
628                 , m_limits                      (memoryLimits)
629                 , m_totalMemTracker     (totalMemTracker)
630                 , m_usage                       (0)
631         {
632         }
633
634         ~MemoryHeap (void)
635         {
636                 for (vector<MemoryObject*>::iterator iter = m_objects.begin(); iter != m_objects.end(); ++iter)
637                         delete *iter;
638         }
639
640         bool                                                            full                    (void) const { return getAvailableMem() == 0;   }
641         bool                                                            empty                   (void) const { return m_usage == 0;                             }
642
643         MemoryObject*                                           allocateRandom  (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
644         {
645                 const VkDeviceSize              availableMem    = getAvailableMem();
646
647                 DE_ASSERT(availableMem > 0);
648
649                 const VkDeviceSize              size                    = 1ull + (rng.getUint64() % availableMem);
650                 const deUint32                  type                    = rng.choose<deUint32>(m_memoryTypes.begin(), m_memoryTypes.end());
651
652                 DE_ASSERT(size <= availableMem);
653
654                 MemoryObject* const             object  = new MemoryObject(vkd, device, size, type);
655
656                 m_usage += size;
657                 m_totalMemTracker.allocate(getMemoryClass(), size);
658                 m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, size * REFERENCE_BYTES_PER_BYTE);
659                 m_objects.push_back(object);
660
661                 return object;
662         }
663
664         MemoryObject*                                           getRandomObject (de::Random& rng) const
665         {
666                 return rng.choose<MemoryObject*>(m_objects.begin(), m_objects.end());
667         }
668
669         void                                                            free                    (MemoryObject* object)
670         {
671                 removeFirstEqual(m_objects, object);
672                 m_usage -= object->getSize();
673                 m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, object->getSize() * REFERENCE_BYTES_PER_BYTE);
674                 m_totalMemTracker.free(getMemoryClass(), object->getSize());
675                 delete object;
676         }
677
678 private:
679         MemoryClass                                                     getMemoryClass  (void) const
680         {
681                 if ((m_heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
682                         return MEMORY_CLASS_DEVICE;
683                 else
684                         return MEMORY_CLASS_SYSTEM;
685         }
686
687         VkDeviceSize                                            getAvailableMem (void) const
688         {
689                 DE_ASSERT(m_usage <= m_heap.size/MAX_MEMORY_USAGE_DIV);
690
691                 const VkDeviceSize      availableInHeap = m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage;
692                 const bool                      isUMA                   = m_limits.totalDeviceLocalMemory == 0;
693
694                 if (isUMA)
695                 {
696                         const VkDeviceSize      totalUsage      = m_totalMemTracker.getTotalUsage();
697                         const VkDeviceSize      totalSysMem     = (VkDeviceSize)m_limits.totalSystemMemory;
698
699                         DE_ASSERT(totalUsage <= totalSysMem);
700
701                         return de::min(availableInHeap, (totalSysMem-totalUsage) / (1 + REFERENCE_BYTES_PER_BYTE));
702                 }
703                 else
704                 {
705                         const VkDeviceSize      totalUsage              = m_totalMemTracker.getTotalUsage();
706                         const VkDeviceSize      totalSysMem             = (VkDeviceSize)m_limits.totalSystemMemory;
707
708                         const MemoryClass       memClass                = getMemoryClass();
709                         const VkDeviceSize      totalMemClass   = memClass == MEMORY_CLASS_SYSTEM
710                                                                                                 ? (VkDeviceSize)(m_limits.totalSystemMemory / (1 + REFERENCE_BYTES_PER_BYTE))
711                                                                                                 : m_limits.totalDeviceLocalMemory;
712                         const VkDeviceSize      usedMemClass    = m_totalMemTracker.getUsage(memClass);
713
714                         DE_ASSERT(usedMemClass <= totalMemClass);
715
716                         return de::min(de::min(availableInHeap, totalMemClass-usedMemClass), (totalSysMem - totalUsage) / REFERENCE_BYTES_PER_BYTE);
717                 }
718         }
719
720         const VkMemoryHeap                      m_heap;
721         const vector<deUint32>          m_memoryTypes;
722         const PlatformMemoryLimits&     m_limits;
723         TotalMemoryTracker&                     m_totalMemTracker;
724
725         VkDeviceSize                            m_usage;
726         vector<MemoryObject*>           m_objects;
727 };
728
729 size_t getMemoryObjectSystemSize (Context& context)
730 {
731         return computeDeviceMemorySystemMemFootprint(context.getDeviceInterface(), context.getDevice())
732                    + sizeof(MemoryObject)
733                    + sizeof(de::SharedPtr<MemoryObject>);
734 }
735
736 size_t getMemoryMappingSystemSize (void)
737 {
738         return sizeof(MemoryMapping) + sizeof(de::SharedPtr<MemoryMapping>);
739 }
740
741 class RandomMemoryMappingInstance : public TestInstance
742 {
743 public:
744         RandomMemoryMappingInstance (Context& context, deUint32 seed)
745                 : TestInstance                          (context)
746                 , m_memoryObjectSysMemSize      (getMemoryObjectSystemSize(context))
747                 , m_memoryMappingSysMemSize     (getMemoryMappingSystemSize())
748                 , m_memoryLimits                        (getMemoryLimits(context.getTestContext().getPlatform().getVulkanPlatform()))
749                 , m_rng                                         (seed)
750                 , m_opNdx                                       (0)
751         {
752                 const VkPhysicalDevice                                  physicalDevice          = context.getPhysicalDevice();
753                 const InstanceInterface&                                vki                                     = context.getInstanceInterface();
754                 const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
755
756                 // Initialize heaps
757                 {
758                         vector<vector<deUint32> >       memoryTypes     (memoryProperties.memoryHeapCount);
759
760                         for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
761                         {
762                                 if (memoryProperties.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
763                                         memoryTypes[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].push_back(memoryTypeNdx);
764                         }
765
766                         for (deUint32 heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; heapIndex++)
767                         {
768                                 const VkMemoryHeap      heapInfo        = memoryProperties.memoryHeaps[heapIndex];
769
770                                 if (!memoryTypes[heapIndex].empty())
771                                 {
772                                         const de::SharedPtr<MemoryHeap> heap    (new MemoryHeap(heapInfo, memoryTypes[heapIndex], m_memoryLimits, m_totalMemTracker));
773
774                                         TCU_CHECK_INTERNAL(!heap->full());
775
776                                         m_memoryHeaps.push_back(heap);
777                                 }
778                         }
779                 }
780         }
781
782         ~RandomMemoryMappingInstance (void)
783         {
784         }
785
786         tcu::TestStatus iterate (void)
787         {
788                 const size_t                    opCount                                         = 100;
789                 const float                             memoryOpProbability                     = 0.5f;         // 0.50
790                 const float                             flushInvalidateProbability      = 0.4f;         // 0.20
791                 const float                             mapProbability                          = 0.50f;        // 0.15
792                 const float                             unmapProbability                        = 0.25f;        // 0.075
793
794                 const float                             allocProbability                        = 0.75f; // Versun free
795
796                 const VkDevice                  device                                          = m_context.getDevice();
797                 const DeviceInterface&  vkd                                                     = m_context.getDeviceInterface();
798
799                 const VkDeviceSize              sysMemUsage                                     = (m_memoryLimits.totalDeviceLocalMemory == 0)
800                                                                                                                         ? m_totalMemTracker.getTotalUsage()
801                                                                                                                         : m_totalMemTracker.getUsage(MEMORY_CLASS_SYSTEM);
802
803                 if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
804                 {
805                         // Perform operations on mapped memory
806                         MemoryMapping* const    mapping = m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
807
808                         enum Op
809                         {
810                                 OP_READ = 0,
811                                 OP_WRITE,
812                                 OP_MODIFY,
813                                 OP_LAST
814                         };
815
816                         const Op op = (Op)(m_rng.getUint32() % OP_LAST);
817
818                         switch (op)
819                         {
820                                 case OP_READ:
821                                         mapping->randomRead(m_rng);
822                                         break;
823
824                                 case OP_WRITE:
825                                         mapping->randomWrite(m_rng);
826                                         break;
827
828                                 case OP_MODIFY:
829                                         mapping->randomModify(m_rng);
830                                         break;
831
832                                 default:
833                                         DE_FATAL("Invalid operation");
834                         }
835                 }
836                 else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
837                 {
838                         MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
839
840                         if (m_rng.getBool())
841                                 object->randomFlush(vkd, device, m_rng);
842                         else
843                                 object->randomInvalidate(vkd, device, m_rng);
844                 }
845                 else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
846                 {
847                         // Unmap memory object
848                         MemoryObject* const     object  = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
849
850                         // Remove mapping
851                         removeFirstEqual(m_memoryMappings, object->getMapping());
852
853                         object->unmap();
854                         removeFirstEqual(m_mappedMemoryObjects, object);
855                         m_nonMappedMemoryObjects.push_back(object);
856
857                         m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
858                 }
859                 else if (!m_nonMappedMemoryObjects.empty() &&
860                                  (m_rng.getFloat() < mapProbability) &&
861                                  (sysMemUsage+m_memoryMappingSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory))
862                 {
863                         // Map memory object
864                         MemoryObject* const             object  = m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
865                         MemoryMapping*                  mapping = object->mapRandom(vkd, device, m_rng);
866
867                         m_memoryMappings.push_back(mapping);
868                         m_mappedMemoryObjects.push_back(object);
869                         removeFirstEqual(m_nonMappedMemoryObjects, object);
870
871                         m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
872                 }
873                 else
874                 {
875                         // Sort heaps based on capacity (full or not)
876                         vector<MemoryHeap*>             nonFullHeaps;
877                         vector<MemoryHeap*>             nonEmptyHeaps;
878
879                         if (sysMemUsage+m_memoryObjectSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory)
880                         {
881                                 // For the duration of sorting reserve MemoryObject space from system memory
882                                 m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
883
884                                 for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
885                                          heapIter != m_memoryHeaps.end();
886                                          ++heapIter)
887                                 {
888                                         if (!(*heapIter)->full())
889                                                 nonFullHeaps.push_back(heapIter->get());
890
891                                         if (!(*heapIter)->empty())
892                                                 nonEmptyHeaps.push_back(heapIter->get());
893                                 }
894
895                                 m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
896                         }
897                         else
898                         {
899                                 // Not possible to even allocate MemoryObject from system memory, look for non-empty heaps
900                                 for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
901                                          heapIter != m_memoryHeaps.end();
902                                          ++heapIter)
903                                 {
904                                         if (!(*heapIter)->empty())
905                                                 nonEmptyHeaps.push_back(heapIter->get());
906                                 }
907                         }
908
909                         if (!nonFullHeaps.empty() && (nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
910                         {
911                                 // Reserve MemoryObject from sys mem first
912                                 m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
913
914                                 // Allocate more memory objects
915                                 MemoryHeap* const       heap    = m_rng.choose<MemoryHeap*>(nonFullHeaps.begin(), nonFullHeaps.end());
916                                 MemoryObject* const     object  = heap->allocateRandom(vkd, device, m_rng);
917
918                                 m_nonMappedMemoryObjects.push_back(object);
919                         }
920                         else
921                         {
922                                 // Free memory objects
923                                 MemoryHeap* const               heap    = m_rng.choose<MemoryHeap*>(nonEmptyHeaps.begin(), nonEmptyHeaps.end());
924                                 MemoryObject* const             object  = heap->getRandomObject(m_rng);
925
926                                 // Remove mapping
927                                 if (object->getMapping())
928                                 {
929                                         removeFirstEqual(m_memoryMappings, object->getMapping());
930                                         m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, m_memoryMappingSysMemSize);
931                                 }
932
933                                 removeFirstEqual(m_mappedMemoryObjects, object);
934                                 removeFirstEqual(m_nonMappedMemoryObjects, object);
935
936                                 heap->free(object);
937                                 m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
938                         }
939                 }
940
941                 m_opNdx += 1;
942                 if (m_opNdx == opCount)
943                         return tcu::TestStatus::pass("Pass");
944                 else
945                         return tcu::TestStatus::incomplete();
946         }
947
948 private:
949         const size_t                                            m_memoryObjectSysMemSize;
950         const size_t                                            m_memoryMappingSysMemSize;
951         const PlatformMemoryLimits                      m_memoryLimits;
952
953         de::Random                                                      m_rng;
954         size_t                                                          m_opNdx;
955
956         TotalMemoryTracker                                      m_totalMemTracker;
957         vector<de::SharedPtr<MemoryHeap> >      m_memoryHeaps;
958
959         vector<MemoryObject*>                           m_mappedMemoryObjects;
960         vector<MemoryObject*>                           m_nonMappedMemoryObjects;
961         vector<MemoryMapping*>                          m_memoryMappings;
962 };
963
964 enum Op
965 {
966         OP_NONE = 0,
967
968         OP_FLUSH,
969         OP_SUB_FLUSH,
970         OP_SUB_FLUSH_SEPARATE,
971         OP_SUB_FLUSH_OVERLAPPING,
972
973         OP_INVALIDATE,
974         OP_SUB_INVALIDATE,
975         OP_SUB_INVALIDATE_SEPARATE,
976         OP_SUB_INVALIDATE_OVERLAPPING,
977
978         OP_REMAP,
979
980         OP_LAST
981 };
982
983 TestConfig subMappedConfig (VkDeviceSize                                allocationSize,
984                                                         const MemoryRange&                      mapping,
985                                                         Op                                                      op,
986                                                         deUint32                                        seed)
987 {
988         TestConfig config;
989
990         config.allocationSize   = allocationSize;
991         config.seed                             = seed;
992         config.mapping                  = mapping;
993         config.remap                    = false;
994
995         switch (op)
996         {
997                 case OP_NONE:
998                         return config;
999
1000                 case OP_REMAP:
1001                         config.remap = true;
1002                         return config;
1003
1004                 case OP_FLUSH:
1005                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset, mapping.size));
1006                         return config;
1007
1008                 case OP_SUB_FLUSH:
1009                         DE_ASSERT(mapping.size / 4 > 0);
1010
1011                         config.flushMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset + mapping.size / 4, mapping.size / 2));
1012                         return config;
1013
1014                 case OP_SUB_FLUSH_SEPARATE:
1015                         DE_ASSERT(mapping.size / 2 > 0);
1016
1017                         config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  2, mapping.size - (mapping.size / 2)));
1018                         config.flushMappings.push_back(MemoryRange(mapping.offset, mapping.size / 2));
1019
1020                         return config;
1021
1022                 case OP_SUB_FLUSH_OVERLAPPING:
1023                         DE_ASSERT((mapping.size / 3) > 0);
1024
1025                         config.flushMappings.push_back(MemoryRange(mapping.offset + mapping.size /  3, mapping.size - (mapping.size / 2)));
1026                         config.flushMappings.push_back(MemoryRange(mapping.offset, (2 * mapping.size) / 3));
1027
1028                         return config;
1029
1030                 case OP_INVALIDATE:
1031                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset, mapping.size));
1032                         return config;
1033
1034                 case OP_SUB_INVALIDATE:
1035                         DE_ASSERT(mapping.size / 4 > 0);
1036
1037                         config.invalidateMappings = vector<MemoryRange>(1, MemoryRange(mapping.offset + mapping.size / 4, mapping.size / 2));
1038                         return config;
1039
1040                 case OP_SUB_INVALIDATE_SEPARATE:
1041                         DE_ASSERT(mapping.size / 2 > 0);
1042
1043                         config.invalidateMappings.push_back(MemoryRange(mapping.offset + mapping.size /  2, mapping.size - (mapping.size / 2)));
1044                         config.invalidateMappings.push_back(MemoryRange(mapping.offset, mapping.size / 2));
1045
1046                         return config;
1047
1048                 case OP_SUB_INVALIDATE_OVERLAPPING:
1049                         DE_ASSERT((mapping.size / 3) > 0);
1050
1051                         config.invalidateMappings.push_back(MemoryRange(mapping.offset + mapping.size /  3, mapping.size - (mapping.size / 2)));
1052                         config.invalidateMappings.push_back(MemoryRange(mapping.offset, (2 * mapping.size) / 3));
1053
1054                         return config;
1055
1056                 default:
1057                         DE_FATAL("Unknown Op");
1058                         return TestConfig();
1059         }
1060 }
1061
1062 TestConfig fullMappedConfig (VkDeviceSize       allocationSize,
1063                                                          Op                             op,
1064                                                          deUint32               seed)
1065 {
1066         return subMappedConfig(allocationSize, MemoryRange(0, allocationSize), op, seed);
1067 }
1068
1069 } // anonymous
1070
1071 tcu::TestCaseGroup* createMappingTests (tcu::TestContext& testCtx)
1072 {
1073         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "mapping", "Memory mapping tests."));
1074
1075         const VkDeviceSize allocationSizes[] =
1076         {
1077                 33, 257, 4087, 8095, 1*1024*1024 + 1
1078         };
1079
1080         const VkDeviceSize offsets[] =
1081         {
1082                 0, 17, 129, 255, 1025, 32*1024+1
1083         };
1084
1085         const VkDeviceSize sizes[] =
1086         {
1087                 31, 255, 1025, 4085, 1*1024*1024 - 1
1088         };
1089
1090         const struct
1091         {
1092                 const Op                        op;
1093                 const char* const       name;
1094         } ops[] =
1095         {
1096                 { OP_NONE,                                              "simple"                                        },
1097                 { OP_REMAP,                                             "remap"                                         },
1098                 { OP_FLUSH,                                             "flush"                                         },
1099                 { OP_SUB_FLUSH,                                 "subflush"                                      },
1100                 { OP_SUB_FLUSH_SEPARATE,                "subflush_separate"                     },
1101                 { OP_SUB_FLUSH_SEPARATE,                "subflush_overlapping"          },
1102
1103                 { OP_INVALIDATE,                                "invalidate"                            },
1104                 { OP_SUB_INVALIDATE,                    "subinvalidate"                         },
1105                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_separate"        },
1106                 { OP_SUB_INVALIDATE_SEPARATE,   "subinvalidate_overlapping"     }
1107         };
1108
1109         // .full
1110         {
1111                 de::MovePtr<tcu::TestCaseGroup> fullGroup (new tcu::TestCaseGroup(testCtx, "full", "Map memory completely."));
1112
1113                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
1114                 {
1115                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
1116                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
1117
1118                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
1119                         {
1120                                 const Op                        op              = ops[opNdx].op;
1121                                 const char* const       name    = ops[opNdx].name;
1122                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
1123                                 const TestConfig        config  = fullMappedConfig(allocationSize, op, seed);
1124
1125                                 addFunctionCase(allocationSizeGroup.get(), name, name, testMemoryMapping, config);
1126                         }
1127
1128                         fullGroup->addChild(allocationSizeGroup.release());
1129                 }
1130
1131                 group->addChild(fullGroup.release());
1132         }
1133
1134         // .sub
1135         {
1136                 de::MovePtr<tcu::TestCaseGroup> subGroup (new tcu::TestCaseGroup(testCtx, "sub", "Map part of the memory."));
1137
1138                 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
1139                 {
1140                         const VkDeviceSize                              allocationSize          = allocationSizes[allocationSizeNdx];
1141                         de::MovePtr<tcu::TestCaseGroup> allocationSizeGroup     (new tcu::TestCaseGroup(testCtx, de::toString(allocationSize).c_str(), ""));
1142
1143                         for (size_t offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++)
1144                         {
1145                                 const VkDeviceSize                              offset                  = offsets[offsetNdx];
1146
1147                                 if (offset >= allocationSize)
1148                                         continue;
1149
1150                                 de::MovePtr<tcu::TestCaseGroup> offsetGroup             (new tcu::TestCaseGroup(testCtx, ("offset_" + de::toString(offset)).c_str(), ""));
1151
1152                                 for (size_t sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); sizeNdx++)
1153                                 {
1154                                         const VkDeviceSize                              size            = sizes[sizeNdx];
1155
1156                                         if (offset + size > allocationSize)
1157                                                 continue;
1158
1159                                         if (offset == 0 && size == allocationSize)
1160                                                 continue;
1161
1162                                         de::MovePtr<tcu::TestCaseGroup> sizeGroup       (new tcu::TestCaseGroup(testCtx, ("size_" + de::toString(size)).c_str(), ""));
1163
1164                                         for (size_t opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
1165                                         {
1166                                                 const deUint32          seed    = (deUint32)(opNdx * allocationSizeNdx);
1167                                                 const Op                        op              = ops[opNdx].op;
1168                                                 const char* const       name    = ops[opNdx].name;
1169                                                 const TestConfig        config  = subMappedConfig(allocationSize, MemoryRange(offset, size), op, seed);
1170
1171                                                 addFunctionCase(sizeGroup.get(), name, name, testMemoryMapping, config);
1172                                         }
1173
1174                                         offsetGroup->addChild(sizeGroup.release());
1175                                 }
1176
1177                                 allocationSizeGroup->addChild(offsetGroup.release());
1178                         }
1179
1180                         subGroup->addChild(allocationSizeGroup.release());
1181                 }
1182
1183                 group->addChild(subGroup.release());
1184         }
1185
1186         // .random
1187         {
1188                 de::MovePtr<tcu::TestCaseGroup> randomGroup     (new tcu::TestCaseGroup(testCtx, "random", "Random memory mapping tests."));
1189                 de::Random                                              rng                     (3927960301u);
1190
1191                 for (size_t ndx = 0; ndx < 100; ndx++)
1192                 {
1193                         const deUint32          seed    = rng.getUint32();
1194                         const std::string       name    = de::toString(ndx);
1195
1196                         randomGroup->addChild(new InstanceFactory1<RandomMemoryMappingInstance, deUint32>(testCtx, tcu::NODETYPE_SELF_VALIDATE, de::toString(ndx), "Random case", seed));
1197                 }
1198
1199                 group->addChild(randomGroup.release());
1200         }
1201
1202         return group.release();
1203 }
1204
1205 } // memory
1206 } // vkt