1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 // This is a GPU-backend specific test. It relies on static intializers to work
9 
10 #include "SkTypes.h"
11 
12 #if SK_SUPPORT_GPU && defined(SK_VULKAN)
13 
14 #include "GrContextPriv.h"
15 #include "GrContextFactory.h"
16 #include "GrTest.h"
17 #include "Test.h"
18 #include "vk/GrVkGpu.h"
19 
20 using sk_gpu_test::GrContextFactory;
21 
subheap_test(skiatest::Reporter * reporter,GrContext * context)22 void subheap_test(skiatest::Reporter* reporter, GrContext* context) {
23     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
24 
25     // memtype doesn't matter, we're just testing the suballocation algorithm so we'll use 0
26     GrVkSubHeap heap(gpu, 0, 0, 64 * 1024, 32);
27     GrVkAlloc alloc0, alloc1, alloc2, alloc3;
28     // test full allocation and free
29     REPORTER_ASSERT(reporter, heap.alloc(64 * 1024, &alloc0));
30     REPORTER_ASSERT(reporter, alloc0.fOffset == 0);
31     REPORTER_ASSERT(reporter, alloc0.fSize == 64 * 1024);
32     REPORTER_ASSERT(reporter, heap.freeSize() == 0 && heap.largestBlockSize() == 0);
33     heap.free(alloc0);
34     REPORTER_ASSERT(reporter, heap.freeSize() == 64*1024 && heap.largestBlockSize() == 64 * 1024);
35 
36     // now let's suballoc some memory
37     REPORTER_ASSERT(reporter, heap.alloc(16 * 1024, &alloc0));
38     REPORTER_ASSERT(reporter, heap.alloc(23 * 1024, &alloc1));
39     REPORTER_ASSERT(reporter, heap.alloc(18 * 1024, &alloc2));
40     REPORTER_ASSERT(reporter, heap.freeSize() == 7 * 1024 && heap.largestBlockSize() == 7 * 1024);
41     // free lone block
42     heap.free(alloc1);
43     REPORTER_ASSERT(reporter, heap.freeSize() == 30 * 1024 && heap.largestBlockSize() == 23 * 1024);
44     // allocate into smallest free block
45     REPORTER_ASSERT(reporter, heap.alloc(6 * 1024, &alloc3));
46     REPORTER_ASSERT(reporter, heap.freeSize() == 24 * 1024 && heap.largestBlockSize() == 23 * 1024);
47     // allocate into exact size free block
48     REPORTER_ASSERT(reporter, heap.alloc(23 * 1024, &alloc1));
49     REPORTER_ASSERT(reporter, heap.freeSize() == 1 * 1024 && heap.largestBlockSize() == 1 * 1024);
50     // free lone block
51     heap.free(alloc2);
52     REPORTER_ASSERT(reporter, heap.freeSize() == 19 * 1024 && heap.largestBlockSize() == 18 * 1024);
53     // free and merge with preceding block and following
54     heap.free(alloc3);
55     REPORTER_ASSERT(reporter, heap.freeSize() == 25 * 1024 && heap.largestBlockSize() == 25 * 1024);
56     // free and merge with following block
57     heap.free(alloc1);
58     REPORTER_ASSERT(reporter, heap.freeSize() == 48 * 1024 && heap.largestBlockSize() == 48 * 1024);
59     // free starting block and merge with following
60     heap.free(alloc0);
61     REPORTER_ASSERT(reporter, heap.freeSize() == 64 * 1024 && heap.largestBlockSize() == 64 * 1024);
62 
63     // realloc
64     REPORTER_ASSERT(reporter, heap.alloc(4 * 1024, &alloc0));
65     REPORTER_ASSERT(reporter, heap.alloc(35 * 1024, &alloc1));
66     REPORTER_ASSERT(reporter, heap.alloc(10 * 1024, &alloc2));
67     REPORTER_ASSERT(reporter, heap.freeSize() == 15 * 1024 && heap.largestBlockSize() == 15 * 1024);
68     // free starting block and merge with following
69     heap.free(alloc0);
70     REPORTER_ASSERT(reporter, heap.freeSize() == 19 * 1024 && heap.largestBlockSize() == 15 * 1024);
71     // free block and merge with preceding
72     heap.free(alloc1);
73     REPORTER_ASSERT(reporter, heap.freeSize() == 54 * 1024 && heap.largestBlockSize() == 39 * 1024);
74     // free block and merge with preceding and following
75     heap.free(alloc2);
76     REPORTER_ASSERT(reporter, heap.freeSize() == 64 * 1024 && heap.largestBlockSize() == 64 * 1024);
77 
78     // fragment
79     REPORTER_ASSERT(reporter, heap.alloc(19 * 1024, &alloc0));
80     REPORTER_ASSERT(reporter, heap.alloc(5 * 1024, &alloc1));
81     REPORTER_ASSERT(reporter, heap.alloc(15 * 1024, &alloc2));
82     REPORTER_ASSERT(reporter, heap.alloc(3 * 1024, &alloc3));
83     REPORTER_ASSERT(reporter, heap.freeSize() == 22 * 1024 && heap.largestBlockSize() == 22 * 1024);
84     heap.free(alloc0);
85     REPORTER_ASSERT(reporter, heap.freeSize() == 41 * 1024 && heap.largestBlockSize() == 22 * 1024);
86     heap.free(alloc2);
87     REPORTER_ASSERT(reporter, heap.freeSize() == 56 * 1024 && heap.largestBlockSize() == 22 * 1024);
88     REPORTER_ASSERT(reporter, !heap.alloc(40 * 1024, &alloc0));
89     heap.free(alloc3);
90     REPORTER_ASSERT(reporter, heap.freeSize() == 59 * 1024 && heap.largestBlockSize() == 40 * 1024);
91     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, &alloc0));
92     REPORTER_ASSERT(reporter, heap.freeSize() == 19 * 1024 && heap.largestBlockSize() == 19 * 1024);
93     heap.free(alloc1);
94     REPORTER_ASSERT(reporter, heap.freeSize() == 24 * 1024 && heap.largestBlockSize() == 24 * 1024);
95     heap.free(alloc0);
96     REPORTER_ASSERT(reporter, heap.freeSize() == 64 * 1024 && heap.largestBlockSize() == 64 * 1024);
97 
98     // unaligned sizes
99     REPORTER_ASSERT(reporter, heap.alloc(19 * 1024 - 31, &alloc0));
100     REPORTER_ASSERT(reporter, heap.alloc(5 * 1024 - 5, &alloc1));
101     REPORTER_ASSERT(reporter, heap.alloc(15 * 1024 - 19, &alloc2));
102     REPORTER_ASSERT(reporter, heap.alloc(3 * 1024 - 3, &alloc3));
103     REPORTER_ASSERT(reporter, heap.freeSize() == 22 * 1024 && heap.largestBlockSize() == 22 * 1024);
104     heap.free(alloc0);
105     REPORTER_ASSERT(reporter, heap.freeSize() == 41 * 1024 && heap.largestBlockSize() == 22 * 1024);
106     heap.free(alloc2);
107     REPORTER_ASSERT(reporter, heap.freeSize() == 56 * 1024 && heap.largestBlockSize() == 22 * 1024);
108     REPORTER_ASSERT(reporter, !heap.alloc(40 * 1024, &alloc0));
109     heap.free(alloc3);
110     REPORTER_ASSERT(reporter, heap.freeSize() == 59 * 1024 && heap.largestBlockSize() == 40 * 1024);
111     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, &alloc0));
112     REPORTER_ASSERT(reporter, heap.freeSize() == 19 * 1024 && heap.largestBlockSize() == 19 * 1024);
113     heap.free(alloc1);
114     REPORTER_ASSERT(reporter, heap.freeSize() == 24 * 1024 && heap.largestBlockSize() == 24 * 1024);
115     heap.free(alloc0);
116     REPORTER_ASSERT(reporter, heap.freeSize() == 64 * 1024 && heap.largestBlockSize() == 64 * 1024);
117 }
118 
suballoc_test(skiatest::Reporter * reporter,GrContext * context)119 void suballoc_test(skiatest::Reporter* reporter, GrContext* context) {
120     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
121 
122     // memtype/heap index don't matter, we're just testing the allocation algorithm so we'll use 0
123     GrVkHeap heap(gpu, GrVkHeap::kSubAlloc_Strategy, 64 * 1024);
124     GrVkAlloc alloc0, alloc1, alloc2, alloc3;
125     const VkDeviceSize kAlignment = 16;
126     const uint32_t kMemType = 0;
127     const uint32_t kHeapIndex = 0;
128 
129     REPORTER_ASSERT(reporter, heap.allocSize() == 0 && heap.usedSize() == 0);
130 
131     // fragment allocations so we need to grow heap
132     REPORTER_ASSERT(reporter, heap.alloc(19 * 1024 - 3, kAlignment, kMemType, kHeapIndex, &alloc0));
133     REPORTER_ASSERT(reporter, heap.alloc(5 * 1024 - 9, kAlignment, kMemType, kHeapIndex, &alloc1));
134     REPORTER_ASSERT(reporter, heap.alloc(15 * 1024 - 15, kAlignment, kMemType, kHeapIndex, &alloc2));
135     REPORTER_ASSERT(reporter, heap.alloc(3 * 1024 - 6, kAlignment, kMemType, kHeapIndex, &alloc3));
136     REPORTER_ASSERT(reporter, heap.allocSize() == 64 * 1024 && heap.usedSize() == 42 * 1024);
137     heap.free(alloc0);
138     REPORTER_ASSERT(reporter, heap.allocSize() == 64 * 1024 && heap.usedSize() == 23 * 1024);
139     heap.free(alloc2);
140     REPORTER_ASSERT(reporter, heap.allocSize() == 64 * 1024 && heap.usedSize() == 8 * 1024);
141     // we expect the heap to grow here
142     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, kAlignment, kMemType, kHeapIndex, &alloc0));
143     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 48 * 1024);
144     heap.free(alloc3);
145     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 45 * 1024);
146     // heap should not grow here (first subheap has exactly enough room)
147     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, kAlignment, kMemType, kHeapIndex, &alloc3));
148     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 85 * 1024);
149     // heap should not grow here (second subheap has room)
150     REPORTER_ASSERT(reporter, heap.alloc(22 * 1024, kAlignment, kMemType, kHeapIndex, &alloc2));
151     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 107 * 1024);
152     heap.free(alloc1);
153     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 102 * 1024);
154     heap.free(alloc0);
155     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 62 * 1024);
156     heap.free(alloc2);
157     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 40 * 1024);
158     heap.free(alloc3);
159     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 0 * 1024);
160     // heap should not grow here (allocating more than subheap size)
161     REPORTER_ASSERT(reporter, heap.alloc(128 * 1024, kAlignment, kMemType, kHeapIndex, &alloc0));
162     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 0 * 1024);
163     heap.free(alloc0);
164     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, kAlignment, kMemType, kHeapIndex, &alloc0));
165     REPORTER_ASSERT(reporter, heap.allocSize() == 128 * 1024 && heap.usedSize() == 24 * 1024);
166     // heap should alloc a new subheap because the memory type is different
167     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, kAlignment, kMemType+1, kHeapIndex, &alloc1));
168     REPORTER_ASSERT(reporter, heap.allocSize() == 192 * 1024 && heap.usedSize() == 48 * 1024);
169     // heap should alloc a new subheap because the alignment is different
170     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, 128, kMemType, kHeapIndex, &alloc2));
171     REPORTER_ASSERT(reporter, heap.allocSize() == 256 * 1024 && heap.usedSize() == 72 * 1024);
172     heap.free(alloc2);
173     heap.free(alloc0);
174     heap.free(alloc1);
175     REPORTER_ASSERT(reporter, heap.allocSize() == 256 * 1024 && heap.usedSize() == 0 * 1024);
176 }
177 
singlealloc_test(skiatest::Reporter * reporter,GrContext * context)178 void singlealloc_test(skiatest::Reporter* reporter, GrContext* context) {
179     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
180 
181     // memtype/heap index don't matter, we're just testing the allocation algorithm so we'll use 0
182     GrVkHeap heap(gpu, GrVkHeap::kSingleAlloc_Strategy, 64 * 1024);
183     GrVkAlloc alloc0, alloc1, alloc2, alloc3;
184     const VkDeviceSize kAlignment = 64;
185     const uint32_t kMemType = 0;
186     const uint32_t kHeapIndex = 0;
187 
188     REPORTER_ASSERT(reporter, heap.allocSize() == 0 && heap.usedSize() == 0);
189 
190     // make a few allocations
191     REPORTER_ASSERT(reporter, heap.alloc(49 * 1024 - 3, kAlignment, kMemType, kHeapIndex, &alloc0));
192     REPORTER_ASSERT(reporter, heap.alloc(5 * 1024 - 37, kAlignment, kMemType, kHeapIndex, &alloc1));
193     REPORTER_ASSERT(reporter, heap.alloc(15 * 1024 - 11, kAlignment, kMemType, kHeapIndex, &alloc2));
194     REPORTER_ASSERT(reporter, heap.alloc(3 * 1024 - 29, kAlignment, kMemType, kHeapIndex, &alloc3));
195     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 72 * 1024);
196     heap.free(alloc0);
197     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 23 * 1024);
198     heap.free(alloc2);
199     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 8 * 1024);
200     // heap should not grow here (first subheap has room)
201     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, kAlignment, kMemType, kHeapIndex, &alloc0));
202     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 48 * 1024);
203     heap.free(alloc3);
204     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 45 * 1024);
205     // check for exact fit -- heap should not grow here (third subheap has room)
206     REPORTER_ASSERT(reporter, heap.alloc(15 * 1024 - 63, kAlignment, kMemType, kHeapIndex, &alloc2));
207     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 60 * 1024);
208     heap.free(alloc2);
209     REPORTER_ASSERT(reporter, heap.allocSize() == 72 * 1024 && heap.usedSize() == 45 * 1024);
210     // heap should grow here (no subheap has room)
211     REPORTER_ASSERT(reporter, heap.alloc(40 * 1024, kAlignment, kMemType, kHeapIndex, &alloc3));
212     REPORTER_ASSERT(reporter, heap.allocSize() == 112 * 1024 && heap.usedSize() == 85 * 1024);
213     heap.free(alloc1);
214     REPORTER_ASSERT(reporter, heap.allocSize() == 112 * 1024 && heap.usedSize() == 80 * 1024);
215     heap.free(alloc0);
216     REPORTER_ASSERT(reporter, heap.allocSize() == 112 * 1024 && heap.usedSize() == 40 * 1024);
217     heap.free(alloc3);
218     REPORTER_ASSERT(reporter, heap.allocSize() == 112 * 1024 && heap.usedSize() == 0 * 1024);
219     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, kAlignment, kMemType, kHeapIndex, &alloc0));
220     REPORTER_ASSERT(reporter, heap.allocSize() == 112 * 1024 && heap.usedSize() == 24 * 1024);
221     // heap should alloc a new subheap because the memory type is different
222     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, kAlignment, kMemType + 1, kHeapIndex, &alloc1));
223     REPORTER_ASSERT(reporter, heap.allocSize() == 136 * 1024 && heap.usedSize() == 48 * 1024);
224     // heap should alloc a new subheap because the alignment is different
225     REPORTER_ASSERT(reporter, heap.alloc(24 * 1024, 128, kMemType, kHeapIndex, &alloc2));
226     REPORTER_ASSERT(reporter, heap.allocSize() == 160 * 1024 && heap.usedSize() == 72 * 1024);
227     heap.free(alloc1);
228     heap.free(alloc2);
229     heap.free(alloc0);
230     REPORTER_ASSERT(reporter, heap.allocSize() == 160 * 1024 && heap.usedSize() == 0 * 1024);
231 }
232 
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkHeapTests,reporter,ctxInfo)233 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkHeapTests, reporter, ctxInfo) {
234     subheap_test(reporter, ctxInfo.grContext());
235     suballoc_test(reporter, ctxInfo.grContext());
236     singlealloc_test(reporter, ctxInfo.grContext());
237 }
238 
239 #endif
240