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#ifndef GrVkMemory_DEFINED
9#define GrVkMemory_DEFINED
10
11#include "GrVkBuffer.h"
12#include "SkTArray.h"
13#include "SkTLList.h"
14#include "vk/GrVkDefines.h"
15#include "vk/GrVkTypes.h"
16
17class GrVkGpu;
18
19namespace GrVkMemory {
20    /**
21    * Allocates vulkan device memory and binds it to the gpu's device for the given object.
22    * Returns true if allocation succeeded.
23    */
24    bool AllocAndBindBufferMemory(const GrVkGpu* gpu,
25                                  VkBuffer buffer,
26                                  GrVkBuffer::Type type,
27                                  bool dynamic,
28                                  GrVkAlloc* alloc);
29    void FreeBufferMemory(const GrVkGpu* gpu, GrVkBuffer::Type type, const GrVkAlloc& alloc);
30
31    bool AllocAndBindImageMemory(const GrVkGpu* gpu,
32                                 VkImage image,
33                                 bool linearTiling,
34                                 GrVkAlloc* alloc);
35    void FreeImageMemory(const GrVkGpu* gpu, bool linearTiling, const GrVkAlloc& alloc);
36
37    VkPipelineStageFlags LayoutToPipelineStageFlags(const VkImageLayout layout);
38
39    VkAccessFlags LayoutToSrcAccessMask(const VkImageLayout layout);
40
41    void FlushMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc);
42    void InvalidateMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc);
43}
44
45class GrVkFreeListAlloc {
46public:
47    GrVkFreeListAlloc(VkDeviceSize size, VkDeviceSize alignment)
48        : fSize(size)
49        , fAlignment(alignment)
50        , fFreeSize(size)
51        , fLargestBlockSize(size)
52        , fLargestBlockOffset(0) {
53        Block* block = fFreeList.addToTail();
54        block->fOffset = 0;
55        block->fSize = fSize;
56    }
57    ~GrVkFreeListAlloc() {
58        this->reset();
59    }
60
61    VkDeviceSize size() const { return fSize; }
62    VkDeviceSize alignment() const { return fAlignment; }
63    VkDeviceSize freeSize() const { return fFreeSize; }
64    VkDeviceSize largestBlockSize() const { return fLargestBlockSize; }
65
66    bool unallocated() const { return fSize == fFreeSize; }
67
68protected:
69    bool alloc(VkDeviceSize requestedSize, VkDeviceSize* allocOffset, VkDeviceSize* allocSize);
70    void free(VkDeviceSize allocOffset, VkDeviceSize allocSize);
71
72    void reset() {
73        fSize = 0;
74        fAlignment = 0;
75        fFreeSize = 0;
76        fLargestBlockSize = 0;
77        fFreeList.reset();
78    }
79
80    struct Block {
81        VkDeviceSize fOffset;
82        VkDeviceSize fSize;
83    };
84    typedef SkTLList<Block, 16> FreeList;
85
86    VkDeviceSize   fSize;
87    VkDeviceSize   fAlignment;
88    VkDeviceSize   fFreeSize;
89    VkDeviceSize   fLargestBlockSize;
90    VkDeviceSize   fLargestBlockOffset;
91    FreeList       fFreeList;
92};
93
94class GrVkSubHeap : public GrVkFreeListAlloc {
95public:
96    GrVkSubHeap(const GrVkGpu* gpu, uint32_t memoryTypeIndex, uint32_t heapIndex,
97                VkDeviceSize size, VkDeviceSize alignment);
98    ~GrVkSubHeap();
99
100    uint32_t memoryTypeIndex() const { return fMemoryTypeIndex; }
101    VkDeviceMemory memory() { return fAlloc; }
102
103    bool alloc(VkDeviceSize requestedSize, GrVkAlloc* alloc);
104    void free(const GrVkAlloc& alloc);
105
106private:
107    const GrVkGpu* fGpu;
108#ifdef SK_DEBUG
109    uint32_t       fHeapIndex;
110#endif
111    uint32_t       fMemoryTypeIndex;
112    VkDeviceMemory fAlloc;
113
114    typedef GrVkFreeListAlloc INHERITED;
115};
116
117class GrVkHeap {
118public:
119    enum Strategy {
120        kSubAlloc_Strategy,       // alloc large subheaps and suballoc within them
121        kSingleAlloc_Strategy     // alloc/recycle an individual subheap per object
122    };
123
124    GrVkHeap(const GrVkGpu* gpu, Strategy strategy, VkDeviceSize subHeapSize)
125        : fGpu(gpu)
126        , fSubHeapSize(subHeapSize)
127        , fAllocSize(0)
128        , fUsedSize(0) {
129        if (strategy == kSubAlloc_Strategy) {
130            fAllocFunc = &GrVkHeap::subAlloc;
131        } else {
132            fAllocFunc = &GrVkHeap::singleAlloc;
133        }
134    }
135
136    ~GrVkHeap() {}
137
138    VkDeviceSize allocSize() const { return fAllocSize; }
139    VkDeviceSize usedSize() const { return fUsedSize; }
140
141    bool alloc(VkDeviceSize size, VkDeviceSize alignment, uint32_t memoryTypeIndex,
142               uint32_t heapIndex, GrVkAlloc* alloc) {
143        SkASSERT(size > 0);
144        return (*this.*fAllocFunc)(size, alignment, memoryTypeIndex, heapIndex, alloc);
145    }
146    bool free(const GrVkAlloc& alloc);
147
148private:
149    typedef bool (GrVkHeap::*AllocFunc)(VkDeviceSize size, VkDeviceSize alignment,
150                                        uint32_t memoryTypeIndex, uint32_t heapIndex,
151                                        GrVkAlloc* alloc);
152
153    bool subAlloc(VkDeviceSize size, VkDeviceSize alignment,
154                  uint32_t memoryTypeIndex, uint32_t heapIndex,
155                  GrVkAlloc* alloc);
156    bool singleAlloc(VkDeviceSize size, VkDeviceSize alignment,
157                     uint32_t memoryTypeIndex, uint32_t heapIndex,
158                     GrVkAlloc* alloc);
159
160    const GrVkGpu*         fGpu;
161    VkDeviceSize           fSubHeapSize;
162    VkDeviceSize           fAllocSize;
163    VkDeviceSize           fUsedSize;
164    AllocFunc              fAllocFunc;
165    SkTArray<std::unique_ptr<GrVkSubHeap>> fSubHeaps;
166};
167#endif
168