xref: /aosp_15_r20/external/skia/src/gpu/vk/VulkanMemory.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/vk/VulkanMemoryAllocator.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/vk/VulkanTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/vk/VulkanMemory.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker using BufferUsage = VulkanMemoryAllocator::BufferUsage;
20*c8dee2aaSAndroid Build Coastguard Worker 
AllocBufferMemory(VulkanMemoryAllocator * allocator,VkBuffer buffer,skgpu::Protected isProtected,BufferUsage usage,bool shouldPersistentlyMapCpuToGpu,const std::function<CheckResult> & checkResult,VulkanAlloc * alloc)21*c8dee2aaSAndroid Build Coastguard Worker bool VulkanMemory::AllocBufferMemory(VulkanMemoryAllocator* allocator,
22*c8dee2aaSAndroid Build Coastguard Worker                                      VkBuffer buffer,
23*c8dee2aaSAndroid Build Coastguard Worker                                      skgpu::Protected isProtected,
24*c8dee2aaSAndroid Build Coastguard Worker                                      BufferUsage usage,
25*c8dee2aaSAndroid Build Coastguard Worker                                      bool shouldPersistentlyMapCpuToGpu,
26*c8dee2aaSAndroid Build Coastguard Worker                                      const std::function<CheckResult>& checkResult,
27*c8dee2aaSAndroid Build Coastguard Worker                                      VulkanAlloc* alloc) {
28*c8dee2aaSAndroid Build Coastguard Worker     VulkanBackendMemory memory = 0;
29*c8dee2aaSAndroid Build Coastguard Worker     uint32_t propFlags;
30*c8dee2aaSAndroid Build Coastguard Worker     if (usage == BufferUsage::kTransfersFromCpuToGpu ||
31*c8dee2aaSAndroid Build Coastguard Worker         (usage == BufferUsage::kCpuWritesGpuReads && shouldPersistentlyMapCpuToGpu)) {
32*c8dee2aaSAndroid Build Coastguard Worker         // In general it is always fine (and often better) to keep buffers always mapped that we are
33*c8dee2aaSAndroid Build Coastguard Worker         // writing to on the cpu.
34*c8dee2aaSAndroid Build Coastguard Worker         propFlags = VulkanMemoryAllocator::kPersistentlyMapped_AllocationPropertyFlag;
35*c8dee2aaSAndroid Build Coastguard Worker     } else {
36*c8dee2aaSAndroid Build Coastguard Worker         propFlags = VulkanMemoryAllocator::kNone_AllocationPropertyFlag;
37*c8dee2aaSAndroid Build Coastguard Worker     }
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker     if (isProtected == Protected::kYes) {
40*c8dee2aaSAndroid Build Coastguard Worker         propFlags = propFlags | VulkanMemoryAllocator::kProtected_AllocationPropertyFlag;
41*c8dee2aaSAndroid Build Coastguard Worker     }
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     VkResult result = allocator->allocateBufferMemory(buffer, usage, propFlags, &memory);
44*c8dee2aaSAndroid Build Coastguard Worker     if (!checkResult(result)) {
45*c8dee2aaSAndroid Build Coastguard Worker         return false;
46*c8dee2aaSAndroid Build Coastguard Worker     }
47*c8dee2aaSAndroid Build Coastguard Worker     allocator->getAllocInfo(memory, alloc);
48*c8dee2aaSAndroid Build Coastguard Worker     return true;
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker 
FreeBufferMemory(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc)51*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::FreeBufferMemory(VulkanMemoryAllocator* allocator, const VulkanAlloc& alloc) {
52*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(alloc.fBackendMemory);
53*c8dee2aaSAndroid Build Coastguard Worker     allocator->freeMemory(alloc.fBackendMemory);
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker 
AllocImageMemory(VulkanMemoryAllocator * allocator,VkImage image,Protected isProtected,bool forceDedicatedMemory,bool useLazyAllocation,const std::function<CheckResult> & checkResult,VulkanAlloc * alloc)56*c8dee2aaSAndroid Build Coastguard Worker bool VulkanMemory::AllocImageMemory(VulkanMemoryAllocator* allocator,
57*c8dee2aaSAndroid Build Coastguard Worker                                     VkImage image,
58*c8dee2aaSAndroid Build Coastguard Worker                                     Protected isProtected,
59*c8dee2aaSAndroid Build Coastguard Worker                                     bool forceDedicatedMemory,
60*c8dee2aaSAndroid Build Coastguard Worker                                     bool useLazyAllocation,
61*c8dee2aaSAndroid Build Coastguard Worker                                     const std::function<CheckResult>& checkResult,
62*c8dee2aaSAndroid Build Coastguard Worker                                     VulkanAlloc* alloc) {
63*c8dee2aaSAndroid Build Coastguard Worker     VulkanBackendMemory memory = 0;
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     uint32_t propFlags;
66*c8dee2aaSAndroid Build Coastguard Worker     // If we ever find that our allocator is not aggressive enough in using dedicated image
67*c8dee2aaSAndroid Build Coastguard Worker     // memory we can add a size check here to force the use of dedicate memory. However for now,
68*c8dee2aaSAndroid Build Coastguard Worker     // we let the allocators decide. The allocator can query the GPU for each image to see if the
69*c8dee2aaSAndroid Build Coastguard Worker     // GPU recommends or requires the use of dedicated memory.
70*c8dee2aaSAndroid Build Coastguard Worker     if (forceDedicatedMemory) {
71*c8dee2aaSAndroid Build Coastguard Worker         propFlags = VulkanMemoryAllocator::kDedicatedAllocation_AllocationPropertyFlag;
72*c8dee2aaSAndroid Build Coastguard Worker     } else {
73*c8dee2aaSAndroid Build Coastguard Worker         propFlags = VulkanMemoryAllocator::kNone_AllocationPropertyFlag;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     if (isProtected == Protected::kYes) {
77*c8dee2aaSAndroid Build Coastguard Worker         propFlags = propFlags | VulkanMemoryAllocator::kProtected_AllocationPropertyFlag;
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     if (useLazyAllocation) {
81*c8dee2aaSAndroid Build Coastguard Worker         propFlags = propFlags | VulkanMemoryAllocator::kLazyAllocation_AllocationPropertyFlag;
82*c8dee2aaSAndroid Build Coastguard Worker     }
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker     VkResult result = allocator->allocateImageMemory(image, propFlags, &memory);
85*c8dee2aaSAndroid Build Coastguard Worker     if (!checkResult(result)) {
86*c8dee2aaSAndroid Build Coastguard Worker         return false;
87*c8dee2aaSAndroid Build Coastguard Worker     }
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker     allocator->getAllocInfo(memory, alloc);
90*c8dee2aaSAndroid Build Coastguard Worker     return true;
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
FreeImageMemory(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc)93*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::FreeImageMemory(VulkanMemoryAllocator* allocator,
94*c8dee2aaSAndroid Build Coastguard Worker                                    const VulkanAlloc& alloc) {
95*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(alloc.fBackendMemory);
96*c8dee2aaSAndroid Build Coastguard Worker     allocator->freeMemory(alloc.fBackendMemory);
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker 
MapAlloc(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc,const std::function<CheckResult> & checkResult)99*c8dee2aaSAndroid Build Coastguard Worker void* VulkanMemory::MapAlloc(VulkanMemoryAllocator* allocator,
100*c8dee2aaSAndroid Build Coastguard Worker                              const VulkanAlloc& alloc,
101*c8dee2aaSAndroid Build Coastguard Worker                              const std::function<CheckResult>& checkResult) {
102*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(VulkanAlloc::kMappable_Flag & alloc.fFlags);
103*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(alloc.fBackendMemory);
104*c8dee2aaSAndroid Build Coastguard Worker     void* mapPtr;
105*c8dee2aaSAndroid Build Coastguard Worker     VkResult result = allocator->mapMemory(alloc.fBackendMemory, &mapPtr);
106*c8dee2aaSAndroid Build Coastguard Worker     if (!checkResult(result)) {
107*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
108*c8dee2aaSAndroid Build Coastguard Worker     }
109*c8dee2aaSAndroid Build Coastguard Worker     return mapPtr;
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker 
UnmapAlloc(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc)112*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::UnmapAlloc(VulkanMemoryAllocator* allocator,
113*c8dee2aaSAndroid Build Coastguard Worker                               const VulkanAlloc& alloc) {
114*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(alloc.fBackendMemory);
115*c8dee2aaSAndroid Build Coastguard Worker     allocator->unmapMemory(alloc.fBackendMemory);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker 
GetNonCoherentMappedMemoryRange(const VulkanAlloc & alloc,VkDeviceSize offset,VkDeviceSize size,VkDeviceSize alignment,VkMappedMemoryRange * range)118*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::GetNonCoherentMappedMemoryRange(const VulkanAlloc& alloc,
119*c8dee2aaSAndroid Build Coastguard Worker                                                    VkDeviceSize offset,
120*c8dee2aaSAndroid Build Coastguard Worker                                                    VkDeviceSize size,
121*c8dee2aaSAndroid Build Coastguard Worker                                                    VkDeviceSize alignment,
122*c8dee2aaSAndroid Build Coastguard Worker                                                    VkMappedMemoryRange* range) {
123*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(alloc.fFlags & VulkanAlloc::kNoncoherent_Flag);
124*c8dee2aaSAndroid Build Coastguard Worker     offset = offset + alloc.fOffset;
125*c8dee2aaSAndroid Build Coastguard Worker     VkDeviceSize offsetDiff = offset & (alignment -1);
126*c8dee2aaSAndroid Build Coastguard Worker     offset = offset - offsetDiff;
127*c8dee2aaSAndroid Build Coastguard Worker     size = (size + alignment - 1) & ~(alignment - 1);
128*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
129*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(offset >= alloc.fOffset);
130*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(offset + size <= alloc.fOffset + alloc.fSize);
131*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(0 == (offset & (alignment-1)));
132*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(size > 0);
133*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(0 == (size & (alignment-1)));
134*c8dee2aaSAndroid Build Coastguard Worker #endif
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker     std::memset(range, 0, sizeof(VkMappedMemoryRange));
137*c8dee2aaSAndroid Build Coastguard Worker     range->sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
138*c8dee2aaSAndroid Build Coastguard Worker     range->memory = alloc.fMemory;
139*c8dee2aaSAndroid Build Coastguard Worker     range->offset = offset;
140*c8dee2aaSAndroid Build Coastguard Worker     range->size = size;
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker 
FlushMappedAlloc(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc,VkDeviceSize offset,VkDeviceSize size,const std::function<CheckResult> & checkResult)143*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::FlushMappedAlloc(VulkanMemoryAllocator* allocator,
144*c8dee2aaSAndroid Build Coastguard Worker                                     const VulkanAlloc& alloc,
145*c8dee2aaSAndroid Build Coastguard Worker                                     VkDeviceSize offset,
146*c8dee2aaSAndroid Build Coastguard Worker                                     VkDeviceSize size,
147*c8dee2aaSAndroid Build Coastguard Worker                                     const std::function<CheckResult>& checkResult) {
148*c8dee2aaSAndroid Build Coastguard Worker     if (alloc.fFlags & VulkanAlloc::kNoncoherent_Flag) {
149*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(offset == 0);
150*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(size <= alloc.fSize);
151*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(alloc.fBackendMemory);
152*c8dee2aaSAndroid Build Coastguard Worker         VkResult result = allocator->flushMemory(alloc.fBackendMemory, offset, size);
153*c8dee2aaSAndroid Build Coastguard Worker         checkResult(result);
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
InvalidateMappedAlloc(VulkanMemoryAllocator * allocator,const VulkanAlloc & alloc,VkDeviceSize offset,VkDeviceSize size,const std::function<CheckResult> & checkResult)157*c8dee2aaSAndroid Build Coastguard Worker void VulkanMemory::InvalidateMappedAlloc(VulkanMemoryAllocator* allocator,
158*c8dee2aaSAndroid Build Coastguard Worker                                          const VulkanAlloc& alloc,
159*c8dee2aaSAndroid Build Coastguard Worker                                          VkDeviceSize offset,
160*c8dee2aaSAndroid Build Coastguard Worker                                          VkDeviceSize size,
161*c8dee2aaSAndroid Build Coastguard Worker                                          const std::function<CheckResult>& checkResult) {
162*c8dee2aaSAndroid Build Coastguard Worker     if (alloc.fFlags & VulkanAlloc::kNoncoherent_Flag) {
163*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(offset == 0);
164*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(size <= alloc.fSize);
165*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(alloc.fBackendMemory);
166*c8dee2aaSAndroid Build Coastguard Worker         VkResult result = allocator->invalidateMemory(alloc.fBackendMemory, offset, size);
167*c8dee2aaSAndroid Build Coastguard Worker         checkResult(result);
168*c8dee2aaSAndroid Build Coastguard Worker     }
169*c8dee2aaSAndroid Build Coastguard Worker }
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu
172