1 /*
2  * Copyright 2018 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 #ifndef GrVkMemoryAllocator_DEFINED
9 #define GrVkMemoryAllocator_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "include/core/SkString.h"
13 #include "include/gpu/GrTypes.h"
14 #include "include/gpu/vk/GrVkTypes.h"
15 
16 class GrVkMemoryAllocator : public SkRefCnt {
17 public:
18     enum class AllocationPropertyFlags {
19         kNone                = 0,
20         // Allocation will be placed in its own VkDeviceMemory and not suballocated from some larger
21         // block.
22         kDedicatedAllocation = 0x1,
23         // Says that the backing memory can only be accessed by the device. Additionally the device
24         // may lazily allocate the memory. This cannot be used with buffers that will be host
25         // visible. Setting this flag does not guarantee that we will allocate memory that respects
26         // it, but we will try to prefer memory that can respect it.
27         kLazyAllocation      = 0x2,
28         // The allocation will be mapped immediately and stay mapped until it is destroyed. This
29         // flag is only valid for buffers which are host visible (i.e. must have a usage other than
30         // BufferUsage::kGpuOnly).
31         kPersistentlyMapped  = 0x4,
32         // Allocation can only be accessed by the device using a protected context.
33         kProtected  = 0x8,
34     };
35 
36     GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AllocationPropertyFlags);
37 
38     enum class BufferUsage {
39         // Buffers that will only be accessed from the device (large const buffers). Will always be
40         // in device local memory.
41         kGpuOnly,
42         // Buffers that typically will be updated multiple times by the host and read on the gpu
43         // (e.g. uniform or vertex buffers). CPU writes will generally be sequential in the buffer
44         // and will try to take advantage of the write-combined nature of the gpu buffers. Thus this
45         // will always be mappable and coherent memory, and it will prefer to be in device local
46         // memory.
47         kCpuWritesGpuReads,
48         // Buffers that will be accessed on the host and copied to another GPU resource (transfer
49         // buffers). Will always be mappable and coherent memory.
50         kTransfersFromCpuToGpu,
51         // Buffers which are typically writted to by the GPU and then read on the host. Will always
52         // be mappable memory, and will prefer cached memory.
53         kTransfersFromGpuToCpu,
54     };
55 
56     // DEPRECATED: Use and implement allocateImageMemory instead
allocateMemoryForImage(VkImage, AllocationPropertyFlags, GrVkBackendMemory*)57     virtual bool allocateMemoryForImage(VkImage, AllocationPropertyFlags, GrVkBackendMemory*) {
58         // The default implementation here is so clients can delete this virtual as the switch to
59         // the new one which returns a VkResult.
60         return false;
61     }
62 
allocateImageMemory(VkImage image, AllocationPropertyFlags flags, GrVkBackendMemory* memory)63     virtual VkResult allocateImageMemory(VkImage image, AllocationPropertyFlags flags,
64                                          GrVkBackendMemory* memory) {
65         bool result = this->allocateMemoryForImage(image, flags, memory);
66         // VK_ERROR_INITIALIZATION_FAILED is a bogus result to return from this function, but it is
67         // just something to return that is not VK_SUCCESS and can't be interpreted by a caller to
68         // mean something specific happened like device lost or oom. This will be removed once we
69         // update clients to implement this virtual.
70         return result ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
71     }
72 
73     // DEPRECATED: Use and implement allocateBufferMemory instead
allocateMemoryForBuffer(VkBuffer, BufferUsage, AllocationPropertyFlags, GrVkBackendMemory*)74     virtual bool allocateMemoryForBuffer(VkBuffer, BufferUsage,  AllocationPropertyFlags,
75                                          GrVkBackendMemory*) {
76         // The default implementation here is so clients can delete this virtual as the switch to
77         // the new one which returns a VkResult.
78         return false;
79     }
80 
allocateBufferMemory(VkBuffer buffer, BufferUsage usage, AllocationPropertyFlags flags, GrVkBackendMemory* memory)81     virtual VkResult allocateBufferMemory(VkBuffer buffer,
82                                           BufferUsage usage,
83                                           AllocationPropertyFlags flags,
84                                           GrVkBackendMemory* memory) {
85         bool result = this->allocateMemoryForBuffer(buffer, usage, flags, memory);
86         // VK_ERROR_INITIALIZATION_FAILED is a bogus result to return from this function, but it is
87         // just something to return that is not VK_SUCCESS and can't be interpreted by a caller to
88         // mean something specific happened like device lost or oom. This will be removed once we
89         // update clients to implement this virtual.
90         return result ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
91     }
92 
93 
94     // Fills out the passed in GrVkAlloc struct for the passed in GrVkBackendMemory.
95     virtual void getAllocInfo(const GrVkBackendMemory&, GrVkAlloc*) const = 0;
96 
97     // Maps the entire allocation and returns a pointer to the start of the allocation. The
98     // implementation may map more memory than just the allocation, but the returned pointer must
99     // point at the start of the memory for the requested allocation.
mapMemory(const GrVkBackendMemory&)100     virtual void* mapMemory(const GrVkBackendMemory&) { return nullptr; }
mapMemory(const GrVkBackendMemory& memory, void** data)101     virtual VkResult mapMemory(const GrVkBackendMemory& memory, void** data) {
102         *data = this->mapMemory(memory);
103         // VK_ERROR_INITIALIZATION_FAILED is a bogus result to return from this function, but it is
104         // just something to return that is not VK_SUCCESS and can't be interpreted by a caller to
105         // mean something specific happened like device lost or oom. This will be removed once we
106         // update clients to implement this virtual.
107         return *data ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
108     }
109     virtual void unmapMemory(const GrVkBackendMemory&) = 0;
110 
111     // The following two calls are used for managing non-coherent memory. The offset is relative to
112     // the start of the allocation and not the underlying VkDeviceMemory. Additionaly the client
113     // must make sure that the offset + size passed in is less that or equal to the allocation size.
114     // It is the responsibility of the implementation to make sure all alignment requirements are
115     // followed. The client should not have to deal with any sort of alignment issues.
flushMappedMemory(const GrVkBackendMemory&, VkDeviceSize, VkDeviceSize)116     virtual void flushMappedMemory(const GrVkBackendMemory&, VkDeviceSize, VkDeviceSize) {}
flushMemory(const GrVkBackendMemory& memory, VkDeviceSize offset, VkDeviceSize size)117     virtual VkResult flushMemory(const GrVkBackendMemory& memory,  VkDeviceSize offset,
118                                  VkDeviceSize size) {
119         this->flushMappedMemory(memory, offset, size);
120         return VK_SUCCESS;
121     }
invalidateMappedMemory(const GrVkBackendMemory&, VkDeviceSize, VkDeviceSize)122     virtual void invalidateMappedMemory(const GrVkBackendMemory&, VkDeviceSize, VkDeviceSize) {}
invalidateMemory(const GrVkBackendMemory& memory, VkDeviceSize offset, VkDeviceSize size)123     virtual VkResult invalidateMemory(const GrVkBackendMemory& memory,  VkDeviceSize offset,
124                                  VkDeviceSize size) {
125         this->invalidateMappedMemory(memory, offset, size);
126         return VK_SUCCESS;
127     }
128 
129     virtual void freeMemory(const GrVkBackendMemory&) = 0;
130 
131     // Returns the total amount of memory that is allocated and in use by an allocation for this
132     // allocator.
133     virtual uint64_t totalUsedMemory() const = 0;
134 
135     // Returns the total amount of memory that is allocated by this allocator.
136     virtual uint64_t totalAllocatedMemory() const = 0;
137 
vmaDefragment()138     virtual void vmaDefragment() {}
dumpVmaStats(SkString *out, const char *sep = �) const139     virtual void dumpVmaStats(SkString *out, const char *sep = ", ") const {}
140 };
141 
142 GR_MAKE_BITFIELD_CLASS_OPS(GrVkMemoryAllocator::AllocationPropertyFlags)
143 
144 #endif
145