blob: 27641028c002c549614de965832a64b73068abf9 [file] [log] [blame]
Greg Daniel164a9f02016-02-22 09:56:40 -05001/*
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#include "GrVkMemory.h"
9
10#include "GrVkGpu.h"
11#include "GrVkUtil.h"
12
jvanverth68c3d302016-09-23 10:30:04 -070013#ifdef SK_DEBUG
14// for simple tracking of how much we're using in each heap
15// last counter is for non-subheap allocations
16VkDeviceSize gHeapUsage[VK_MAX_MEMORY_HEAPS+1] = { 0 };
17#endif
18
jvanverth9d54afc2016-09-20 09:20:03 -070019static bool get_valid_memory_type_index(const VkPhysicalDeviceMemoryProperties& physDevMemProps,
Greg Daniel164a9f02016-02-22 09:56:40 -050020 uint32_t typeBits,
21 VkMemoryPropertyFlags requestedMemFlags,
jvanverth68c3d302016-09-23 10:30:04 -070022 uint32_t* typeIndex,
23 uint32_t* heapIndex) {
jvanverth9d54afc2016-09-20 09:20:03 -070024 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
25 if (typeBits & (1 << i)) {
Greg Daniel164a9f02016-02-22 09:56:40 -050026 uint32_t supportedFlags = physDevMemProps.memoryTypes[i].propertyFlags &
27 requestedMemFlags;
28 if (supportedFlags == requestedMemFlags) {
29 *typeIndex = i;
jvanverth68c3d302016-09-23 10:30:04 -070030 *heapIndex = physDevMemProps.memoryTypes[i].heapIndex;
Greg Daniel164a9f02016-02-22 09:56:40 -050031 return true;
32 }
33 }
Greg Daniel164a9f02016-02-22 09:56:40 -050034 }
35 return false;
36}
37
jvanverth6b6ffc42016-06-13 14:28:07 -070038static GrVkGpu::Heap buffer_type_to_heap(GrVkBuffer::Type type) {
39 const GrVkGpu::Heap kBufferToHeap[]{
40 GrVkGpu::kVertexBuffer_Heap,
41 GrVkGpu::kIndexBuffer_Heap,
42 GrVkGpu::kUniformBuffer_Heap,
43 GrVkGpu::kCopyReadBuffer_Heap,
44 GrVkGpu::kCopyWriteBuffer_Heap,
Greg Daniel164a9f02016-02-22 09:56:40 -050045 };
jvanverth6b6ffc42016-06-13 14:28:07 -070046 GR_STATIC_ASSERT(0 == GrVkBuffer::kVertex_Type);
47 GR_STATIC_ASSERT(1 == GrVkBuffer::kIndex_Type);
48 GR_STATIC_ASSERT(2 == GrVkBuffer::kUniform_Type);
49 GR_STATIC_ASSERT(3 == GrVkBuffer::kCopyRead_Type);
50 GR_STATIC_ASSERT(4 == GrVkBuffer::kCopyWrite_Type);
Greg Daniel164a9f02016-02-22 09:56:40 -050051
jvanverth6b6ffc42016-06-13 14:28:07 -070052 return kBufferToHeap[type];
Greg Daniel164a9f02016-02-22 09:56:40 -050053}
54
55bool GrVkMemory::AllocAndBindBufferMemory(const GrVkGpu* gpu,
56 VkBuffer buffer,
jvanverth6b6ffc42016-06-13 14:28:07 -070057 GrVkBuffer::Type type,
jvanvertha584de92016-06-30 09:10:52 -070058 bool dynamic,
jvanverth1e305ba2016-06-01 09:39:15 -070059 GrVkAlloc* alloc) {
jvanverthe50f3e72016-03-28 07:03:06 -070060 const GrVkInterface* iface = gpu->vkInterface();
Greg Daniel164a9f02016-02-22 09:56:40 -050061 VkDevice device = gpu->device();
62
63 VkMemoryRequirements memReqs;
jvanverthe50f3e72016-03-28 07:03:06 -070064 GR_VK_CALL(iface, GetBufferMemoryRequirements(device, buffer, &memReqs));
Greg Daniel164a9f02016-02-22 09:56:40 -050065
jvanverth7378ac82016-06-14 08:32:44 -070066 uint32_t typeIndex = 0;
jvanverth68c3d302016-09-23 10:30:04 -070067 uint32_t heapIndex = 0;
jvanverth9d54afc2016-09-20 09:20:03 -070068 const VkPhysicalDeviceMemoryProperties& phDevMemProps = gpu->physicalDeviceMemoryProperties();
69 if (dynamic) {
70 // try to get cached and ideally non-coherent memory first
71 if (!get_valid_memory_type_index(phDevMemProps,
72 memReqs.memoryTypeBits,
73 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
74 VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
jvanverth68c3d302016-09-23 10:30:04 -070075 &typeIndex,
76 &heapIndex)) {
jvanverth9d54afc2016-09-20 09:20:03 -070077 // some sort of host-visible memory type should always be available for dynamic buffers
78 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
79 memReqs.memoryTypeBits,
80 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
jvanverth68c3d302016-09-23 10:30:04 -070081 &typeIndex,
82 &heapIndex));
jvanverth9d54afc2016-09-20 09:20:03 -070083 }
84
85 VkMemoryPropertyFlags mpf = phDevMemProps.memoryTypes[typeIndex].propertyFlags;
86 alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0
87 : GrVkAlloc::kNoncoherent_Flag;
88 } else {
89 // device-local memory should always be available for static buffers
90 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
jvanverth6b6ffc42016-06-13 14:28:07 -070091 memReqs.memoryTypeBits,
jvanverth9d54afc2016-09-20 09:20:03 -070092 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
jvanverth68c3d302016-09-23 10:30:04 -070093 &typeIndex,
94 &heapIndex));
jvanverth9d54afc2016-09-20 09:20:03 -070095 alloc->fFlags = 0x0;
jvanverth6b6ffc42016-06-13 14:28:07 -070096 }
97
98 GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type));
99
jvanverth68c3d302016-09-23 10:30:04 -0700100 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
101 // if static, try to allocate from non-host-visible non-device-local memory instead
102 if (dynamic ||
103 !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits,
104 0, &typeIndex, &heapIndex) ||
105 !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
106 SkDebugf("Failed to alloc buffer\n");
107 return false;
108 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500109 }
110
jvanverth9d54afc2016-09-20 09:20:03 -0700111 // Bind buffer
egdaniel6e90d422016-08-10 08:29:53 -0700112 VkResult err = GR_VK_CALL(iface, BindBufferMemory(device, buffer,
jvanverth1e305ba2016-06-01 09:39:15 -0700113 alloc->fMemory, alloc->fOffset));
Greg Daniel164a9f02016-02-22 09:56:40 -0500114 if (err) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700115 SkASSERT_RELEASE(heap->free(*alloc));
Greg Daniel164a9f02016-02-22 09:56:40 -0500116 return false;
117 }
jvanverth6b6ffc42016-06-13 14:28:07 -0700118
Greg Daniel164a9f02016-02-22 09:56:40 -0500119 return true;
120}
121
jvanverth6b6ffc42016-06-13 14:28:07 -0700122void GrVkMemory::FreeBufferMemory(const GrVkGpu* gpu, GrVkBuffer::Type type,
123 const GrVkAlloc& alloc) {
124
125 GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type));
126 SkASSERT_RELEASE(heap->free(alloc));
127}
128
129// for debugging
130static uint64_t gTotalImageMemory = 0;
131static uint64_t gTotalImageMemoryFullPage = 0;
132
133const VkDeviceSize kMaxSmallImageSize = 16 * 1024;
134const VkDeviceSize kMinVulkanPageSize = 16 * 1024;
135
136static VkDeviceSize align_size(VkDeviceSize size, VkDeviceSize alignment) {
137 return (size + alignment - 1) & ~(alignment - 1);
jvanverth1e305ba2016-06-01 09:39:15 -0700138}
139
Greg Daniel164a9f02016-02-22 09:56:40 -0500140bool GrVkMemory::AllocAndBindImageMemory(const GrVkGpu* gpu,
141 VkImage image,
jvanverth6b6ffc42016-06-13 14:28:07 -0700142 bool linearTiling,
jvanverth1e305ba2016-06-01 09:39:15 -0700143 GrVkAlloc* alloc) {
jvanverthe50f3e72016-03-28 07:03:06 -0700144 const GrVkInterface* iface = gpu->vkInterface();
Greg Daniel164a9f02016-02-22 09:56:40 -0500145 VkDevice device = gpu->device();
146
147 VkMemoryRequirements memReqs;
jvanverthe50f3e72016-03-28 07:03:06 -0700148 GR_VK_CALL(iface, GetImageMemoryRequirements(device, image, &memReqs));
Greg Daniel164a9f02016-02-22 09:56:40 -0500149
jvanverth7378ac82016-06-14 08:32:44 -0700150 uint32_t typeIndex = 0;
jvanverth68c3d302016-09-23 10:30:04 -0700151 uint32_t heapIndex = 0;
jvanverth6b6ffc42016-06-13 14:28:07 -0700152 GrVkHeap* heap;
jvanverth9d54afc2016-09-20 09:20:03 -0700153 const VkPhysicalDeviceMemoryProperties& phDevMemProps = gpu->physicalDeviceMemoryProperties();
jvanverth6b6ffc42016-06-13 14:28:07 -0700154 if (linearTiling) {
155 VkMemoryPropertyFlags desiredMemProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
jvanverth6b6ffc42016-06-13 14:28:07 -0700156 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
jvanverth9d54afc2016-09-20 09:20:03 -0700157 if (!get_valid_memory_type_index(phDevMemProps,
jvanverth6b6ffc42016-06-13 14:28:07 -0700158 memReqs.memoryTypeBits,
159 desiredMemProps,
jvanverth68c3d302016-09-23 10:30:04 -0700160 &typeIndex,
161 &heapIndex)) {
jvanverth9d54afc2016-09-20 09:20:03 -0700162 // some sort of host-visible memory type should always be available
163 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
jvanverth6b6ffc42016-06-13 14:28:07 -0700164 memReqs.memoryTypeBits,
jvanverth9d54afc2016-09-20 09:20:03 -0700165 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
jvanverth68c3d302016-09-23 10:30:04 -0700166 &typeIndex,
167 &heapIndex));
jvanverth6b6ffc42016-06-13 14:28:07 -0700168 }
169 heap = gpu->getHeap(GrVkGpu::kLinearImage_Heap);
jvanverth9d54afc2016-09-20 09:20:03 -0700170 VkMemoryPropertyFlags mpf = phDevMemProps.memoryTypes[typeIndex].propertyFlags;
171 alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0
172 : GrVkAlloc::kNoncoherent_Flag;
jvanverth6b6ffc42016-06-13 14:28:07 -0700173 } else {
174 // this memory type should always be available
jvanverth9d54afc2016-09-20 09:20:03 -0700175 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
jvanverth6b6ffc42016-06-13 14:28:07 -0700176 memReqs.memoryTypeBits,
177 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
jvanverth68c3d302016-09-23 10:30:04 -0700178 &typeIndex,
179 &heapIndex));
jvanverth6b6ffc42016-06-13 14:28:07 -0700180 if (memReqs.size <= kMaxSmallImageSize) {
181 heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap);
182 } else {
183 heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap);
184 }
jvanverth9d54afc2016-09-20 09:20:03 -0700185 alloc->fFlags = 0x0;
jvanverth6b6ffc42016-06-13 14:28:07 -0700186 }
187
jvanverth68c3d302016-09-23 10:30:04 -0700188 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
189 // if optimal, try to allocate from non-host-visible non-device-local memory instead
190 if (linearTiling ||
191 !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits,
192 0, &typeIndex, &heapIndex) ||
193 !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
194 SkDebugf("Failed to alloc image\n");
195 return false;
196 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500197 }
198
jvanverth9d54afc2016-09-20 09:20:03 -0700199 // Bind image
jvanverth1e305ba2016-06-01 09:39:15 -0700200 VkResult err = GR_VK_CALL(iface, BindImageMemory(device, image,
201 alloc->fMemory, alloc->fOffset));
Greg Daniel164a9f02016-02-22 09:56:40 -0500202 if (err) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700203 SkASSERT_RELEASE(heap->free(*alloc));
Greg Daniel164a9f02016-02-22 09:56:40 -0500204 return false;
205 }
jvanverth6b6ffc42016-06-13 14:28:07 -0700206
207 gTotalImageMemory += alloc->fSize;
208
209 VkDeviceSize pageAlignedSize = align_size(alloc->fSize, kMinVulkanPageSize);
210 gTotalImageMemoryFullPage += pageAlignedSize;
211
Greg Daniel164a9f02016-02-22 09:56:40 -0500212 return true;
213}
214
jvanverth6b6ffc42016-06-13 14:28:07 -0700215void GrVkMemory::FreeImageMemory(const GrVkGpu* gpu, bool linearTiling,
216 const GrVkAlloc& alloc) {
217 GrVkHeap* heap;
218 if (linearTiling) {
219 heap = gpu->getHeap(GrVkGpu::kLinearImage_Heap);
220 } else if (alloc.fSize <= kMaxSmallImageSize) {
221 heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap);
222 } else {
223 heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap);
224 }
225 if (!heap->free(alloc)) {
226 // must be an adopted allocation
227 GR_VK_CALL(gpu->vkInterface(), FreeMemory(gpu->device(), alloc.fMemory, nullptr));
228 } else {
229 gTotalImageMemory -= alloc.fSize;
230 VkDeviceSize pageAlignedSize = align_size(alloc.fSize, kMinVulkanPageSize);
231 gTotalImageMemoryFullPage -= pageAlignedSize;
232 }
jvanverth1e305ba2016-06-01 09:39:15 -0700233}
234
Greg Daniel164a9f02016-02-22 09:56:40 -0500235VkPipelineStageFlags GrVkMemory::LayoutToPipelineStageFlags(const VkImageLayout layout) {
236 if (VK_IMAGE_LAYOUT_GENERAL == layout) {
237 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
238 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
239 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
240 return VK_PIPELINE_STAGE_TRANSFER_BIT;
241 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
242 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
243 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
244 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
egdanielbc9b2962016-09-27 08:00:53 -0700245 return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
Greg Daniel164a9f02016-02-22 09:56:40 -0500246 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
247 return VK_PIPELINE_STAGE_HOST_BIT;
248 }
249
250 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
251 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
252}
253
254VkAccessFlags GrVkMemory::LayoutToSrcAccessMask(const VkImageLayout layout) {
255 // Currently we assume we will never being doing any explict shader writes (this doesn't include
256 // color attachment or depth/stencil writes). So we will ignore the
257 // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.
258
259 // We can only directly access the host memory if we are in preinitialized or general layout,
260 // and the image is linear.
261 // TODO: Add check for linear here so we are not always adding host to general, and we should
262 // only be in preinitialized if we are linear
263 VkAccessFlags flags = 0;;
264 if (VK_IMAGE_LAYOUT_GENERAL == layout) {
265 flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
egdaniel19ff1032016-08-31 10:13:08 -0700266 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
267 VK_ACCESS_TRANSFER_WRITE_BIT |
268 VK_ACCESS_TRANSFER_READ_BIT |
269 VK_ACCESS_SHADER_READ_BIT |
270 VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
Greg Daniel164a9f02016-02-22 09:56:40 -0500271 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
egdanielc2fde8b2016-06-24 10:29:02 -0700272 flags = VK_ACCESS_HOST_WRITE_BIT;
Greg Daniel164a9f02016-02-22 09:56:40 -0500273 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
274 flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
275 } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
276 flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
277 } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
278 flags = VK_ACCESS_TRANSFER_WRITE_BIT;
279 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
280 flags = VK_ACCESS_TRANSFER_READ_BIT;
281 } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
282 flags = VK_ACCESS_SHADER_READ_BIT;
283 }
284 return flags;
285}
jvanverth6b6ffc42016-06-13 14:28:07 -0700286
jvanverth9d54afc2016-09-20 09:20:03 -0700287void GrVkMemory::FlushMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc) {
288 if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) {
289 VkMappedMemoryRange mappedMemoryRange;
290 memset(&mappedMemoryRange, 0, sizeof(VkMappedMemoryRange));
291 mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
292 mappedMemoryRange.memory = alloc.fMemory;
293 mappedMemoryRange.offset = alloc.fOffset;
294 mappedMemoryRange.size = alloc.fSize;
295 GR_VK_CALL(gpu->vkInterface(), FlushMappedMemoryRanges(gpu->device(),
296 1, &mappedMemoryRange));
297 }
298}
299
300void GrVkMemory::InvalidateMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc) {
301 if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) {
302 VkMappedMemoryRange mappedMemoryRange;
303 memset(&mappedMemoryRange, 0, sizeof(VkMappedMemoryRange));
304 mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
305 mappedMemoryRange.memory = alloc.fMemory;
306 mappedMemoryRange.offset = alloc.fOffset;
307 mappedMemoryRange.size = alloc.fSize;
308 GR_VK_CALL(gpu->vkInterface(), InvalidateMappedMemoryRanges(gpu->device(),
309 1, &mappedMemoryRange));
310 }
311}
312
jvanverth82356cc2016-07-07 07:16:42 -0700313bool GrVkFreeListAlloc::alloc(VkDeviceSize requestedSize,
314 VkDeviceSize* allocOffset, VkDeviceSize* allocSize) {
315 VkDeviceSize alignedSize = align_size(requestedSize, fAlignment);
jvanverth6b6ffc42016-06-13 14:28:07 -0700316
317 // find the smallest block big enough for our allocation
318 FreeList::Iter iter = fFreeList.headIter();
319 FreeList::Iter bestFitIter;
320 VkDeviceSize bestFitSize = fSize + 1;
321 VkDeviceSize secondLargestSize = 0;
322 VkDeviceSize secondLargestOffset = 0;
323 while (iter.get()) {
324 Block* block = iter.get();
325 // need to adjust size to match desired alignment
326 SkASSERT(align_size(block->fOffset, fAlignment) - block->fOffset == 0);
327 if (block->fSize >= alignedSize && block->fSize < bestFitSize) {
328 bestFitIter = iter;
329 bestFitSize = block->fSize;
330 }
331 if (secondLargestSize < block->fSize && block->fOffset != fLargestBlockOffset) {
332 secondLargestSize = block->fSize;
333 secondLargestOffset = block->fOffset;
334 }
335 iter.next();
336 }
337 SkASSERT(secondLargestSize <= fLargestBlockSize);
338
339 Block* bestFit = bestFitIter.get();
340 if (bestFit) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700341 SkASSERT(align_size(bestFit->fOffset, fAlignment) == bestFit->fOffset);
jvanverth82356cc2016-07-07 07:16:42 -0700342 *allocOffset = bestFit->fOffset;
343 *allocSize = alignedSize;
jvanverth6b6ffc42016-06-13 14:28:07 -0700344 // adjust or remove current block
345 VkDeviceSize originalBestFitOffset = bestFit->fOffset;
346 if (bestFit->fSize > alignedSize) {
347 bestFit->fOffset += alignedSize;
348 bestFit->fSize -= alignedSize;
349 if (fLargestBlockOffset == originalBestFitOffset) {
350 if (bestFit->fSize >= secondLargestSize) {
351 fLargestBlockSize = bestFit->fSize;
352 fLargestBlockOffset = bestFit->fOffset;
353 } else {
354 fLargestBlockSize = secondLargestSize;
355 fLargestBlockOffset = secondLargestOffset;
356 }
357 }
358#ifdef SK_DEBUG
359 VkDeviceSize largestSize = 0;
360 iter = fFreeList.headIter();
361 while (iter.get()) {
362 Block* block = iter.get();
363 if (largestSize < block->fSize) {
364 largestSize = block->fSize;
365 }
366 iter.next();
367 }
caryclarkd6562002016-07-27 12:02:07 -0700368 SkASSERT(largestSize == fLargestBlockSize);
jvanverth6b6ffc42016-06-13 14:28:07 -0700369#endif
370 } else {
371 SkASSERT(bestFit->fSize == alignedSize);
372 if (fLargestBlockOffset == originalBestFitOffset) {
373 fLargestBlockSize = secondLargestSize;
374 fLargestBlockOffset = secondLargestOffset;
375 }
376 fFreeList.remove(bestFit);
377#ifdef SK_DEBUG
378 VkDeviceSize largestSize = 0;
379 iter = fFreeList.headIter();
380 while (iter.get()) {
381 Block* block = iter.get();
382 if (largestSize < block->fSize) {
383 largestSize = block->fSize;
384 }
385 iter.next();
386 }
387 SkASSERT(largestSize == fLargestBlockSize);
388#endif
389 }
390 fFreeSize -= alignedSize;
egdaniel6e46eea2016-07-07 08:12:33 -0700391 SkASSERT(*allocSize > 0);
jvanverth6b6ffc42016-06-13 14:28:07 -0700392
393 return true;
394 }
jvanverth82356cc2016-07-07 07:16:42 -0700395
jvanverth6b6ffc42016-06-13 14:28:07 -0700396 SkDebugf("Can't allocate %d bytes, %d bytes available, largest free block %d\n", alignedSize, fFreeSize, fLargestBlockSize);
397
398 return false;
399}
400
jvanverth82356cc2016-07-07 07:16:42 -0700401void GrVkFreeListAlloc::free(VkDeviceSize allocOffset, VkDeviceSize allocSize) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700402 // find the block right after this allocation
403 FreeList::Iter iter = fFreeList.headIter();
jvanverthd6f80342016-06-16 04:42:30 -0700404 FreeList::Iter prev;
jvanverth82356cc2016-07-07 07:16:42 -0700405 while (iter.get() && iter.get()->fOffset < allocOffset) {
jvanverthd6f80342016-06-16 04:42:30 -0700406 prev = iter;
jvanverth6b6ffc42016-06-13 14:28:07 -0700407 iter.next();
jvanverth82356cc2016-07-07 07:16:42 -0700408 }
jvanverth6b6ffc42016-06-13 14:28:07 -0700409 // we have four cases:
410 // we exactly follow the previous one
411 Block* block;
jvanverth82356cc2016-07-07 07:16:42 -0700412 if (prev.get() && prev.get()->fOffset + prev.get()->fSize == allocOffset) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700413 block = prev.get();
jvanverth82356cc2016-07-07 07:16:42 -0700414 block->fSize += allocSize;
jvanverth6b6ffc42016-06-13 14:28:07 -0700415 if (block->fOffset == fLargestBlockOffset) {
416 fLargestBlockSize = block->fSize;
417 }
418 // and additionally we may exactly precede the next one
jvanverth82356cc2016-07-07 07:16:42 -0700419 if (iter.get() && iter.get()->fOffset == allocOffset + allocSize) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700420 block->fSize += iter.get()->fSize;
421 if (iter.get()->fOffset == fLargestBlockOffset) {
422 fLargestBlockOffset = block->fOffset;
423 fLargestBlockSize = block->fSize;
424 }
425 fFreeList.remove(iter.get());
426 }
427 // or we only exactly proceed the next one
jvanverth82356cc2016-07-07 07:16:42 -0700428 } else if (iter.get() && iter.get()->fOffset == allocOffset + allocSize) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700429 block = iter.get();
jvanverth82356cc2016-07-07 07:16:42 -0700430 block->fSize += allocSize;
jvanverth6b6ffc42016-06-13 14:28:07 -0700431 if (block->fOffset == fLargestBlockOffset) {
jvanverth82356cc2016-07-07 07:16:42 -0700432 fLargestBlockOffset = allocOffset;
jvanverth6b6ffc42016-06-13 14:28:07 -0700433 fLargestBlockSize = block->fSize;
434 }
jvanverth82356cc2016-07-07 07:16:42 -0700435 block->fOffset = allocOffset;
jvanverth6b6ffc42016-06-13 14:28:07 -0700436 // or we fall somewhere in between, with gaps
437 } else {
438 block = fFreeList.addBefore(iter);
jvanverth82356cc2016-07-07 07:16:42 -0700439 block->fOffset = allocOffset;
440 block->fSize = allocSize;
jvanverth6b6ffc42016-06-13 14:28:07 -0700441 }
jvanverth82356cc2016-07-07 07:16:42 -0700442 fFreeSize += allocSize;
jvanverth6b6ffc42016-06-13 14:28:07 -0700443 if (block->fSize > fLargestBlockSize) {
444 fLargestBlockSize = block->fSize;
445 fLargestBlockOffset = block->fOffset;
446 }
447
448#ifdef SK_DEBUG
449 VkDeviceSize largestSize = 0;
450 iter = fFreeList.headIter();
451 while (iter.get()) {
452 Block* block = iter.get();
453 if (largestSize < block->fSize) {
454 largestSize = block->fSize;
455 }
456 iter.next();
457 }
458 SkASSERT(fLargestBlockSize == largestSize);
459#endif
460}
461
jvanverth68c3d302016-09-23 10:30:04 -0700462GrVkSubHeap::GrVkSubHeap(const GrVkGpu* gpu, uint32_t memoryTypeIndex, uint32_t heapIndex,
jvanverth82356cc2016-07-07 07:16:42 -0700463 VkDeviceSize size, VkDeviceSize alignment)
464 : INHERITED(size, alignment)
465 , fGpu(gpu)
jvanverth68c3d302016-09-23 10:30:04 -0700466#ifdef SK_DEBUG
467 , fHeapIndex(heapIndex)
468#endif
jvanverthae6e4862016-09-22 13:45:24 -0700469 , fMemoryTypeIndex(memoryTypeIndex) {
jvanverth82356cc2016-07-07 07:16:42 -0700470
471 VkMemoryAllocateInfo allocInfo = {
472 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType
473 NULL, // pNext
474 size, // allocationSize
475 memoryTypeIndex, // memoryTypeIndex
476 };
477
478 VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateMemory(gpu->device(),
479 &allocInfo,
480 nullptr,
481 &fAlloc));
482 if (VK_SUCCESS != err) {
483 this->reset();
jvanverth68c3d302016-09-23 10:30:04 -0700484 }
485#ifdef SK_DEBUG
486 else {
487 gHeapUsage[heapIndex] += size;
jvanverth82356cc2016-07-07 07:16:42 -0700488 }
jvanverth68c3d302016-09-23 10:30:04 -0700489#endif
jvanverth82356cc2016-07-07 07:16:42 -0700490}
491
492GrVkSubHeap::~GrVkSubHeap() {
493 const GrVkInterface* iface = fGpu->vkInterface();
494 GR_VK_CALL(iface, FreeMemory(fGpu->device(), fAlloc, nullptr));
jvanverth68c3d302016-09-23 10:30:04 -0700495#ifdef SK_DEBUG
496 gHeapUsage[fHeapIndex] -= fSize;
497#endif
jvanverth82356cc2016-07-07 07:16:42 -0700498}
499
500bool GrVkSubHeap::alloc(VkDeviceSize size, GrVkAlloc* alloc) {
501 alloc->fMemory = fAlloc;
502 return INHERITED::alloc(size, &alloc->fOffset, &alloc->fSize);
503}
504
505void GrVkSubHeap::free(const GrVkAlloc& alloc) {
506 SkASSERT(alloc.fMemory == fAlloc);
507
508 INHERITED::free(alloc.fOffset, alloc.fSize);
jvanverth6b6ffc42016-06-13 14:28:07 -0700509}
510
egdaniel6e90d422016-08-10 08:29:53 -0700511bool GrVkHeap::subAlloc(VkDeviceSize size, VkDeviceSize alignment,
jvanverth68c3d302016-09-23 10:30:04 -0700512 uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAlloc* alloc) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700513 VkDeviceSize alignedSize = align_size(size, alignment);
514
jvanverth6dc3af42016-06-16 14:05:09 -0700515 // if requested is larger than our subheap allocation, just alloc directly
516 if (alignedSize > fSubHeapSize) {
517 VkMemoryAllocateInfo allocInfo = {
518 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType
519 NULL, // pNext
520 size, // allocationSize
521 memoryTypeIndex, // memoryTypeIndex
522 };
523
524 VkResult err = GR_VK_CALL(fGpu->vkInterface(), AllocateMemory(fGpu->device(),
525 &allocInfo,
526 nullptr,
527 &alloc->fMemory));
528 if (VK_SUCCESS != err) {
529 return false;
530 }
531 alloc->fOffset = 0;
532 alloc->fSize = 0; // hint that this is not a subheap allocation
jvanverth68c3d302016-09-23 10:30:04 -0700533#ifdef SK_DEBUG
534 gHeapUsage[VK_MAX_MEMORY_HEAPS] += alignedSize;
535#endif
egdaniel6e90d422016-08-10 08:29:53 -0700536
jvanverth6dc3af42016-06-16 14:05:09 -0700537 return true;
538 }
539
jvanverth6b6ffc42016-06-13 14:28:07 -0700540 // first try to find a subheap that fits our allocation request
541 int bestFitIndex = -1;
542 VkDeviceSize bestFitSize = 0x7FFFFFFF;
543 for (auto i = 0; i < fSubHeaps.count(); ++i) {
egdaniel6e90d422016-08-10 08:29:53 -0700544 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex &&
545 fSubHeaps[i]->alignment() == alignment) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700546 VkDeviceSize heapSize = fSubHeaps[i]->largestBlockSize();
jvanverthd6f80342016-06-16 04:42:30 -0700547 if (heapSize >= alignedSize && heapSize < bestFitSize) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700548 bestFitIndex = i;
549 bestFitSize = heapSize;
550 }
551 }
552 }
553
554 if (bestFitIndex >= 0) {
555 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment);
556 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) {
557 fUsedSize += alloc->fSize;
558 return true;
559 }
560 return false;
jvanverth6dc3af42016-06-16 14:05:09 -0700561 }
jvanverth6b6ffc42016-06-13 14:28:07 -0700562
563 // need to allocate a new subheap
Ben Wagner145dbcd2016-11-03 14:40:50 -0400564 std::unique_ptr<GrVkSubHeap>& subHeap = fSubHeaps.push_back();
jvanverth68c3d302016-09-23 10:30:04 -0700565 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, fSubHeapSize, alignment));
jvanverth6dc3af42016-06-16 14:05:09 -0700566 // try to recover from failed allocation by only allocating what we need
567 if (subHeap->size() == 0) {
568 VkDeviceSize alignedSize = align_size(size, alignment);
jvanverth68c3d302016-09-23 10:30:04 -0700569 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment));
jvanverth6dc3af42016-06-16 14:05:09 -0700570 if (subHeap->size() == 0) {
571 return false;
572 }
573 }
jvanverth6b6ffc42016-06-13 14:28:07 -0700574 fAllocSize += fSubHeapSize;
575 if (subHeap->alloc(size, alloc)) {
576 fUsedSize += alloc->fSize;
577 return true;
578 }
579
580 return false;
581}
582
egdaniel6e90d422016-08-10 08:29:53 -0700583bool GrVkHeap::singleAlloc(VkDeviceSize size, VkDeviceSize alignment,
jvanverth68c3d302016-09-23 10:30:04 -0700584 uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAlloc* alloc) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700585 VkDeviceSize alignedSize = align_size(size, alignment);
586
587 // first try to find an unallocated subheap that fits our allocation request
588 int bestFitIndex = -1;
589 VkDeviceSize bestFitSize = 0x7FFFFFFF;
590 for (auto i = 0; i < fSubHeaps.count(); ++i) {
egdaniel6e90d422016-08-10 08:29:53 -0700591 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex &&
592 fSubHeaps[i]->alignment() == alignment &&
593 fSubHeaps[i]->unallocated()) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700594 VkDeviceSize heapSize = fSubHeaps[i]->size();
jvanverthd6f80342016-06-16 04:42:30 -0700595 if (heapSize >= alignedSize && heapSize < bestFitSize) {
jvanverth6b6ffc42016-06-13 14:28:07 -0700596 bestFitIndex = i;
597 bestFitSize = heapSize;
598 }
599 }
600 }
601
602 if (bestFitIndex >= 0) {
603 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment);
604 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) {
605 fUsedSize += alloc->fSize;
606 return true;
607 }
608 return false;
609 }
610
611 // need to allocate a new subheap
Ben Wagner145dbcd2016-11-03 14:40:50 -0400612 std::unique_ptr<GrVkSubHeap>& subHeap = fSubHeaps.push_back();
jvanverth68c3d302016-09-23 10:30:04 -0700613 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment));
jvanverth6b6ffc42016-06-13 14:28:07 -0700614 fAllocSize += alignedSize;
615 if (subHeap->alloc(size, alloc)) {
616 fUsedSize += alloc->fSize;
617 return true;
618 }
619
620 return false;
621}
622
623bool GrVkHeap::free(const GrVkAlloc& alloc) {
jvanverth6dc3af42016-06-16 14:05:09 -0700624 // a size of 0 means we're using the system heap
625 if (0 == alloc.fSize) {
626 const GrVkInterface* iface = fGpu->vkInterface();
627 GR_VK_CALL(iface, FreeMemory(fGpu->device(), alloc.fMemory, nullptr));
628 return true;
629 }
630
jvanverth6b6ffc42016-06-13 14:28:07 -0700631 for (auto i = 0; i < fSubHeaps.count(); ++i) {
632 if (fSubHeaps[i]->memory() == alloc.fMemory) {
633 fSubHeaps[i]->free(alloc);
634 fUsedSize -= alloc.fSize;
635 return true;
636 }
637 }
638
639 return false;
640}
641
642