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