• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_helpers:
7 //   Helper utilitiy classes that manage Vulkan resources.
8 
9 #ifndef LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_
10 #define LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_
11 
12 #include "libANGLE/renderer/vulkan/CommandGraph.h"
13 #include "libANGLE/renderer/vulkan/vk_utils.h"
14 
15 namespace gl
16 {
17 class ImageIndex;
18 }  // namespace gl
19 
20 namespace rx
21 {
22 namespace vk
23 {
24 constexpr VkBufferUsageFlags kVertexBufferUsageFlags =
25     VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
26 constexpr VkBufferUsageFlags kIndexBufferUsageFlags =
27     VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
28 constexpr size_t kVertexBufferAlignment = 4;
29 constexpr size_t kIndexBufferAlignment  = 4;
30 
31 constexpr VkBufferUsageFlags kStagingBufferFlags =
32     VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
33 constexpr size_t kStagingBufferSize = 1024 * 16;
34 
35 struct TextureUnit final
36 {
37     TextureVk *texture;
38     SamplerVk *sampler;
39 };
40 
41 // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer,
42 // you will always write to a previously unused portion. After a series of writes, you must flush
43 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will
44 // last as long or longer than each prior allocation.
45 //
46 // Dynamic buffers are used to implement a variety of data streaming operations in Vulkan, such
47 // as for immediate vertex array and element array data, uniform updates, and other dynamic data.
48 //
49 // Internally dynamic buffers keep a collection of VkBuffers. When we write past the end of a
50 // currently active VkBuffer we keep it until it is no longer in use. We then mark it available
51 // for future allocations in a free list.
52 class BufferHelper;
53 class DynamicBuffer : angle::NonCopyable
54 {
55   public:
56     DynamicBuffer();
57     DynamicBuffer(DynamicBuffer &&other);
58     ~DynamicBuffer();
59 
60     // Init is called after the buffer creation so that the alignment can be specified later.
61     void init(RendererVk *renderer,
62               VkBufferUsageFlags usage,
63               size_t alignment,
64               size_t initialSize,
65               bool hostVisible);
66 
67     // This call will allocate a new region at the end of the buffer. It internally may trigger
68     // a new buffer to be created (which is returned in the optional parameter
69     // `newBufferAllocatedOut`).  The new region will be in the returned buffer at given offset. If
70     // a memory pointer is given, the buffer will be automatically map()ed.
71     angle::Result allocate(ContextVk *contextVk,
72                            size_t sizeInBytes,
73                            uint8_t **ptrOut,
74                            VkBuffer *bufferOut,
75                            VkDeviceSize *offsetOut,
76                            bool *newBufferAllocatedOut);
77 
78     // After a sequence of writes, call flush to ensure the data is visible to the device.
79     angle::Result flush(ContextVk *contextVk);
80 
81     // After a sequence of writes, call invalidate to ensure the data is visible to the host.
82     angle::Result invalidate(ContextVk *contextVk);
83 
84     // This releases resources when they might currently be in use.
85     void release(ContextVk *contextVk);
86     void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
87 
88     // This releases all the buffers that have been allocated since this was last called.
89     void releaseInFlightBuffers(ContextVk *contextVk);
90 
91     // This frees resources immediately.
92     void destroy(VkDevice device);
93 
getCurrentBuffer()94     BufferHelper *getCurrentBuffer() { return mBuffer; }
95 
getAlignment()96     size_t getAlignment() { return mAlignment; }
97     void updateAlignment(RendererVk *renderer, size_t alignment);
98 
99     // For testing only!
100     void setMinimumSizeForTesting(size_t minSize);
101 
102   private:
103     void reset();
104     angle::Result allocateNewBuffer(ContextVk *contextVk);
105     void releaseBufferListToContext(ContextVk *contextVk, std::vector<BufferHelper *> *buffers);
106     void releaseBufferListToDisplay(DisplayVk *display,
107                                     std::vector<GarbageObjectBase> *garbageQueue,
108                                     std::vector<BufferHelper *> *buffers);
109     void destroyBufferList(VkDevice device, std::vector<BufferHelper *> *buffers);
110 
111     VkBufferUsageFlags mUsage;
112     bool mHostVisible;
113     size_t mInitialSize;
114     BufferHelper *mBuffer;
115     uint32_t mNextAllocationOffset;
116     uint32_t mLastFlushOrInvalidateOffset;
117     size_t mSize;
118     size_t mAlignment;
119 
120     std::vector<BufferHelper *> mInFlightBuffers;
121     std::vector<BufferHelper *> mBufferFreeList;
122 };
123 
124 // Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we
125 // allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded
126 // pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must
127 // use set zero and combined Image Samplers must use set 1. We conservatively count each new set
128 // using the maximum number of descriptor sets and buffers with each allocation. Currently: 2
129 // (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers.
130 
131 // Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool.
132 // Can be used to share descriptor pools between multiple ProgramVks and the ContextVk.
133 class DescriptorPoolHelper
134 {
135   public:
136     DescriptorPoolHelper();
137     ~DescriptorPoolHelper();
138 
valid()139     bool valid() { return mDescriptorPool.valid(); }
140 
141     bool hasCapacity(uint32_t descriptorSetCount) const;
142     angle::Result init(Context *context,
143                        const std::vector<VkDescriptorPoolSize> &poolSizes,
144                        uint32_t maxSets);
145     void destroy(VkDevice device);
146     void release(ContextVk *contextVk);
147 
148     angle::Result allocateSets(ContextVk *contextVk,
149                                const VkDescriptorSetLayout *descriptorSetLayout,
150                                uint32_t descriptorSetCount,
151                                VkDescriptorSet *descriptorSetsOut);
152 
updateSerial(Serial serial)153     void updateSerial(Serial serial) { mMostRecentSerial = serial; }
154 
getSerial()155     Serial getSerial() const { return mMostRecentSerial; }
156 
157   private:
158     uint32_t mFreeDescriptorSets;
159     DescriptorPool mDescriptorPool;
160     Serial mMostRecentSerial;
161 };
162 
163 using RefCountedDescriptorPoolHelper  = RefCounted<DescriptorPoolHelper>;
164 using RefCountedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>;
165 
166 class DynamicDescriptorPool final : angle::NonCopyable
167 {
168   public:
169     DynamicDescriptorPool();
170     ~DynamicDescriptorPool();
171 
172     // The DynamicDescriptorPool only handles one pool size at this time.
173     // Note that setSizes[i].descriptorCount is expected to be the number of descriptors in
174     // an individual set.  The pool size will be calculated accordingly.
175     angle::Result init(ContextVk *contextVk,
176                        const VkDescriptorPoolSize *setSizes,
177                        uint32_t setSizeCount);
178     void destroy(VkDevice device);
179     void release(ContextVk *contextVk);
180 
181     // We use the descriptor type to help count the number of free sets.
182     // By convention, sets are indexed according to the constants in vk_cache_utils.h.
allocateSets(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut)183     ANGLE_INLINE angle::Result allocateSets(ContextVk *contextVk,
184                                             const VkDescriptorSetLayout *descriptorSetLayout,
185                                             uint32_t descriptorSetCount,
186                                             RefCountedDescriptorPoolBinding *bindingOut,
187                                             VkDescriptorSet *descriptorSetsOut)
188     {
189         bool ignoreNewPoolAllocated;
190         return allocateSetsAndGetInfo(contextVk, descriptorSetLayout, descriptorSetCount,
191                                       bindingOut, descriptorSetsOut, &ignoreNewPoolAllocated);
192     }
193 
194     // We use the descriptor type to help count the number of free sets.
195     // By convention, sets are indexed according to the constants in vk_cache_utils.h.
196     angle::Result allocateSetsAndGetInfo(ContextVk *contextVk,
197                                          const VkDescriptorSetLayout *descriptorSetLayout,
198                                          uint32_t descriptorSetCount,
199                                          RefCountedDescriptorPoolBinding *bindingOut,
200                                          VkDescriptorSet *descriptorSetsOut,
201                                          bool *newPoolAllocatedOut);
202 
203     // For testing only!
204     void setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool);
205 
206   private:
207     angle::Result allocateNewPool(ContextVk *contextVk);
208 
209     uint32_t mMaxSetsPerPool;
210     size_t mCurrentPoolIndex;
211     std::vector<RefCountedDescriptorPoolHelper *> mDescriptorPools;
212     std::vector<VkDescriptorPoolSize> mPoolSizes;
213 };
214 
215 template <typename Pool>
216 class DynamicallyGrowingPool : angle::NonCopyable
217 {
218   public:
219     DynamicallyGrowingPool();
220     virtual ~DynamicallyGrowingPool();
221 
isValid()222     bool isValid() { return mPoolSize > 0; }
223 
224   protected:
225     angle::Result initEntryPool(Context *contextVk, uint32_t poolSize);
226     void destroyEntryPool();
227 
228     // Checks to see if any pool is already free, in which case it sets it as current pool and
229     // returns true.
230     bool findFreeEntryPool(ContextVk *contextVk);
231 
232     // Allocates a new entry and initializes it with the given pool.
233     angle::Result allocateNewEntryPool(ContextVk *contextVk, Pool &&pool);
234 
235     // Called by the implementation whenever an entry is freed.
236     void onEntryFreed(ContextVk *contextVk, size_t poolIndex);
237 
238     // The pool size, to know when a pool is completely freed.
239     uint32_t mPoolSize;
240 
241     std::vector<Pool> mPools;
242 
243     struct PoolStats
244     {
245         // A count corresponding to each pool indicating how many of its allocated entries
246         // have been freed. Once that value reaches mPoolSize for each pool, that pool is considered
247         // free and reusable.  While keeping a bitset would allow allocation of each index, the
248         // slight runtime overhead of finding free indices is not worth the slight memory overhead
249         // of creating new pools when unnecessary.
250         uint32_t freedCount;
251         // The serial of the renderer is stored on each object free to make sure no
252         // new allocations are made from the pool until it's not in use.
253         Serial serial;
254     };
255     std::vector<PoolStats> mPoolStats;
256 
257     // Index into mPools indicating pool we are currently allocating from.
258     size_t mCurrentPool;
259     // Index inside mPools[mCurrentPool] indicating which index can be allocated next.
260     uint32_t mCurrentFreeEntry;
261 };
262 
263 // DynamicQueryPool allocates indices out of QueryPool as needed.  Once a QueryPool is exhausted,
264 // another is created.  The query pools live permanently, but are recycled as indices get freed.
265 
266 // These are arbitrary default sizes for query pools.
267 constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64;
268 constexpr uint32_t kDefaultTimestampQueryPoolSize = 64;
269 
270 class QueryHelper;
271 
272 class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool>
273 {
274   public:
275     DynamicQueryPool();
276     ~DynamicQueryPool() override;
277 
278     angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize);
279     void destroy(VkDevice device);
280 
281     angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut);
282     void freeQuery(ContextVk *contextVk, QueryHelper *query);
283 
284     // Special allocator that doesn't work with QueryHelper, which is a CommandGraphResource.
285     // Currently only used with RendererVk::GpuEventQuery.
286     angle::Result allocateQuery(ContextVk *contextVk, size_t *poolIndex, uint32_t *queryIndex);
287     void freeQuery(ContextVk *contextVk, size_t poolIndex, uint32_t queryIndex);
288 
getQueryPool(size_t index)289     const QueryPool *getQueryPool(size_t index) const { return &mPools[index]; }
290 
291   private:
292     angle::Result allocateNewPool(ContextVk *contextVk);
293 
294     // Information required to create new query pools
295     VkQueryType mQueryType;
296 };
297 
298 // Queries in vulkan are identified by the query pool and an index for a query within that pool.
299 // Unlike other pools, such as descriptor pools where an allocation returns an independent object
300 // from the pool, the query allocations are not done through a Vulkan function and are only an
301 // integer index.
302 //
303 // Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools
304 // of a fixed size as needed and allocates indices within those pools.
305 //
306 // The QueryHelper class below keeps the pool and index pair together.
307 class QueryHelper final
308 {
309   public:
310     QueryHelper();
311     ~QueryHelper();
312 
313     void init(const DynamicQueryPool *dynamicQueryPool,
314               const size_t queryPoolIndex,
315               uint32_t query);
316     void deinit();
317 
getQueryPool()318     const QueryPool *getQueryPool() const
319     {
320         return mDynamicQueryPool ? mDynamicQueryPool->getQueryPool(mQueryPoolIndex) : nullptr;
321     }
getQuery()322     uint32_t getQuery() const { return mQuery; }
323 
324     // Used only by DynamicQueryPool.
getQueryPoolIndex()325     size_t getQueryPoolIndex() const { return mQueryPoolIndex; }
326 
327     void beginQuery(ContextVk *contextVk);
328     void endQuery(ContextVk *contextVk);
329     void writeTimestamp(ContextVk *contextVk);
330 
getStoredQueueSerial()331     Serial getStoredQueueSerial() { return mMostRecentSerial; }
332     bool hasPendingWork(ContextVk *contextVk);
333 
334   private:
335     const DynamicQueryPool *mDynamicQueryPool;
336     size_t mQueryPoolIndex;
337     uint32_t mQuery;
338     Serial mMostRecentSerial;
339 };
340 
341 // DynamicSemaphorePool allocates semaphores as needed.  It uses a std::vector
342 // as a pool to allocate many semaphores at once.  The pools live permanently,
343 // but are recycled as semaphores get freed.
344 
345 // These are arbitrary default sizes for semaphore pools.
346 constexpr uint32_t kDefaultSemaphorePoolSize = 64;
347 
348 class SemaphoreHelper;
349 
350 class DynamicSemaphorePool final : public DynamicallyGrowingPool<std::vector<Semaphore>>
351 {
352   public:
353     DynamicSemaphorePool();
354     ~DynamicSemaphorePool() override;
355 
356     angle::Result init(ContextVk *contextVk, uint32_t poolSize);
357     void destroy(VkDevice device);
358 
isValid()359     bool isValid() { return mPoolSize > 0; }
360 
361     // autoFree can be used to allocate a semaphore that's expected to be freed at the end of the
362     // frame.  This renders freeSemaphore unnecessary and saves an eventual search.
363     angle::Result allocateSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphoreOut);
364     void freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore);
365 
366   private:
367     angle::Result allocateNewPool(ContextVk *contextVk);
368 };
369 
370 // Semaphores that are allocated from the semaphore pool are encapsulated in a helper object,
371 // keeping track of where in the pool they are allocated from.
372 class SemaphoreHelper final : angle::NonCopyable
373 {
374   public:
375     SemaphoreHelper();
376     ~SemaphoreHelper();
377 
378     SemaphoreHelper(SemaphoreHelper &&other);
379     SemaphoreHelper &operator=(SemaphoreHelper &&other);
380 
381     void init(const size_t semaphorePoolIndex, const Semaphore *semaphore);
382     void deinit();
383 
getSemaphore()384     const Semaphore *getSemaphore() const { return mSemaphore; }
385 
386     // Used only by DynamicSemaphorePool.
getSemaphorePoolIndex()387     size_t getSemaphorePoolIndex() const { return mSemaphorePoolIndex; }
388 
389   private:
390     size_t mSemaphorePoolIndex;
391     const Semaphore *mSemaphore;
392 };
393 
394 // This class' responsibility is to create index buffers needed to support line loops in Vulkan.
395 // In the setup phase of drawing, the createIndexBuffer method should be called with the
396 // current draw call parameters. If an element array buffer is bound for an indexed draw, use
397 // createIndexBufferFromElementArrayBuffer.
398 //
399 // If the user wants to draw a loop between [v1, v2, v3], we will create an indexed buffer with
400 // these indexes: [0, 1, 2, 3, 0] to emulate the loop.
401 class LineLoopHelper final : angle::NonCopyable
402 {
403   public:
404     LineLoopHelper(RendererVk *renderer);
405     ~LineLoopHelper();
406 
407     angle::Result getIndexBufferForDrawArrays(ContextVk *contextVk,
408                                               uint32_t clampedVertexCount,
409                                               GLint firstVertex,
410                                               vk::BufferHelper **bufferOut,
411                                               VkDeviceSize *offsetOut);
412 
413     angle::Result getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
414                                                       BufferVk *elementArrayBufferVk,
415                                                       gl::DrawElementsType glIndexType,
416                                                       int indexCount,
417                                                       intptr_t elementArrayOffset,
418                                                       vk::BufferHelper **bufferOut,
419                                                       VkDeviceSize *bufferOffsetOut,
420                                                       uint32_t *indexCountOut);
421 
422     angle::Result streamIndices(ContextVk *contextVk,
423                                 gl::DrawElementsType glIndexType,
424                                 GLsizei indexCount,
425                                 const uint8_t *srcPtr,
426                                 vk::BufferHelper **bufferOut,
427                                 VkDeviceSize *bufferOffsetOut,
428                                 uint32_t *indexCountOut);
429 
430     void release(ContextVk *contextVk);
431     void destroy(VkDevice device);
432 
433     static void Draw(uint32_t count, vk::CommandBuffer *commandBuffer);
434 
435   private:
436     DynamicBuffer mDynamicIndexBuffer;
437 };
438 
439 class FramebufferHelper;
440 
441 class BufferHelper final : public CommandGraphResource
442 {
443   public:
444     BufferHelper();
445     ~BufferHelper() override;
446 
447     angle::Result init(ContextVk *contextVk,
448                        const VkBufferCreateInfo &createInfo,
449                        VkMemoryPropertyFlags memoryPropertyFlags);
450     void destroy(VkDevice device);
451 
452     void release(ContextVk *contextVk);
453     void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
454 
valid()455     bool valid() const { return mBuffer.valid(); }
getBuffer()456     const Buffer &getBuffer() const { return mBuffer; }
getDeviceMemory()457     const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
getSize()458     VkDeviceSize getSize() const { return mSize; }
459 
460     // Helpers for setting the graph dependencies *and* setting the appropriate barrier.  These are
461     // made for dependencies to non-buffer resources, as only one of two resources participating in
462     // the dependency would require a memory barrier.  Note that onWrite takes read access flags
463     // too, as output buffers could be read as well.
onRead(CommandGraphResource * reader,VkAccessFlags readAccessType)464     void onRead(CommandGraphResource *reader, VkAccessFlags readAccessType)
465     {
466         addReadDependency(reader);
467         onReadAccess(reader, readAccessType);
468     }
onWrite(ContextVk * contextVk,CommandGraphResource * writer,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)469     void onWrite(ContextVk *contextVk,
470                  CommandGraphResource *writer,
471                  VkAccessFlags readAccessType,
472                  VkAccessFlags writeAccessType)
473     {
474         addWriteDependency(writer);
475         onWriteAccess(contextVk, readAccessType, writeAccessType);
476     }
477     // Helper for setting a graph dependency between two buffers.  This is a specialized function as
478     // both buffers may incur a memory barrier.  Using |onRead| followed by |onWrite| between the
479     // buffers is impossible as it would result in a command graph loop.
onReadByBuffer(ContextVk * contextVk,BufferHelper * reader,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)480     void onReadByBuffer(ContextVk *contextVk,
481                         BufferHelper *reader,
482                         VkAccessFlags readAccessType,
483                         VkAccessFlags writeAccessType)
484     {
485         addReadDependency(reader);
486         onReadAccess(reader, readAccessType);
487         reader->onWriteAccess(contextVk, 0, writeAccessType);
488     }
489     // Helper for setting a barrier when different parts of the same buffer is being read from and
490     // written to.
onSelfReadWrite(ContextVk * contextVk,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)491     void onSelfReadWrite(ContextVk *contextVk,
492                          VkAccessFlags readAccessType,
493                          VkAccessFlags writeAccessType)
494     {
495         if (mCurrentReadAccess || mCurrentWriteAccess)
496         {
497             finishCurrentCommands(contextVk);
498         }
499         onWriteAccess(contextVk, readAccessType, writeAccessType);
500     }
501     // Set write access mask when the buffer is modified externally, e.g. by host.  There is no
502     // graph resource to create a dependency to.
onExternalWrite(VkAccessFlags writeAccessType)503     void onExternalWrite(VkAccessFlags writeAccessType) { mCurrentWriteAccess |= writeAccessType; }
504 
505     // Also implicitly sets up the correct barriers.
506     angle::Result copyFromBuffer(ContextVk *contextVk,
507                                  const Buffer &buffer,
508                                  VkAccessFlags bufferAccessType,
509                                  const VkBufferCopy &copyRegion);
510 
511     // Note: currently only one view is allowed.  If needs be, multiple views can be created
512     // based on format.
513     angle::Result initBufferView(ContextVk *contextVk, const Format &format);
514 
getBufferView()515     const BufferView &getBufferView() const
516     {
517         ASSERT(mBufferView.valid());
518         return mBufferView;
519     }
520 
getViewFormat()521     const Format &getViewFormat() const
522     {
523         ASSERT(mViewFormat);
524         return *mViewFormat;
525     }
526 
map(ContextVk * contextVk,uint8_t ** ptrOut)527     angle::Result map(ContextVk *contextVk, uint8_t **ptrOut)
528     {
529         if (!mMappedMemory)
530         {
531             ANGLE_TRY(mapImpl(contextVk));
532         }
533         *ptrOut = mMappedMemory;
534         return angle::Result::Continue;
535     }
536     void unmap(VkDevice device);
537 
538     // After a sequence of writes, call flush to ensure the data is visible to the device.
539     angle::Result flush(ContextVk *contextVk, size_t offset, size_t size);
540 
541     // After a sequence of writes, call invalidate to ensure the data is visible to the host.
542     angle::Result invalidate(ContextVk *contextVk, size_t offset, size_t size);
543 
544   private:
545     angle::Result mapImpl(ContextVk *contextVk);
needsOnReadBarrier(VkAccessFlags readAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)546     bool needsOnReadBarrier(VkAccessFlags readAccessType,
547                             VkAccessFlags *barrierSrcOut,
548                             VkAccessFlags *barrierDstOut)
549     {
550         bool needsBarrier =
551             mCurrentWriteAccess != 0 && (mCurrentReadAccess & readAccessType) != readAccessType;
552 
553         *barrierSrcOut = mCurrentWriteAccess;
554         *barrierDstOut = readAccessType;
555 
556         mCurrentReadAccess |= readAccessType;
557         return needsBarrier;
558     }
onReadAccess(CommandGraphResource * reader,VkAccessFlags readAccessType)559     void onReadAccess(CommandGraphResource *reader, VkAccessFlags readAccessType)
560     {
561         VkAccessFlags barrierSrc, barrierDst;
562         if (needsOnReadBarrier(readAccessType, &barrierSrc, &barrierDst))
563         {
564             reader->addGlobalMemoryBarrier(barrierSrc, barrierDst,
565                                            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
566         }
567     }
568     bool needsOnWriteBarrier(VkAccessFlags readAccessType,
569                              VkAccessFlags writeAccessType,
570                              VkAccessFlags *barrierSrcOut,
571                              VkAccessFlags *barrierDstOut);
572     void onWriteAccess(ContextVk *contextVk,
573                        VkAccessFlags readAccessType,
574                        VkAccessFlags writeAccessType);
575 
576     // Vulkan objects.
577     Buffer mBuffer;
578     BufferView mBufferView;
579     DeviceMemory mDeviceMemory;
580 
581     // Cached properties.
582     VkMemoryPropertyFlags mMemoryPropertyFlags;
583     VkDeviceSize mSize;
584     uint8_t *mMappedMemory;
585     const Format *mViewFormat;
586 
587     // For memory barriers.
588     VkFlags mCurrentWriteAccess;
589     VkFlags mCurrentReadAccess;
590 };
591 
592 // Imagine an image going through a few layout transitions:
593 //
594 //           srcStage 1    dstStage 2          srcStage 2     dstStage 3
595 //  Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
596 //           srcAccess 1  dstAccess 2          srcAccess 2   dstAccess 3
597 //   \_________________  ___________________/
598 //                     \/
599 //               A transition
600 //
601 // Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and
602 // src/dst access masks.  At the moment we decide to transition the image to Layout 2 (i.e.
603 // Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the
604 // image.  To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2.
605 // Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition.
606 //
607 // That is, with the history kept, on every new transition we need 5 pieces of new information:
608 // layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future
609 // transition out from it.  Given the small number of possible combinations of these values, an
610 // enum is used were each value encapsulates these 5 pieces of information:
611 //
612 //                       +--------------------------------+
613 //           srcStage 1  | dstStage 2          srcStage 2 |   dstStage 3
614 //  Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
615 //           srcAccess 1 |dstAccess 2          srcAccess 2|  dstAccess 3
616 //                       +---------------  ---------------+
617 //                                       \/
618 //                                 One enum value
619 //
620 // Note that, while generally dstStage for the to-transition and srcStage for the from-transition
621 // are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively.
622 enum class ImageLayout
623 {
624     Undefined                  = 0,
625     ExternalPreInitialized     = 1,
626     TransferSrc                = 2,
627     TransferDst                = 3,
628     ComputeShaderReadOnly      = 4,
629     ComputeShaderWrite         = 5,
630     AllGraphicsShadersReadOnly = 6,
631     ColorAttachment            = 7,
632     DepthStencilAttachment     = 8,
633     Present                    = 9,
634 
635     InvalidEnum = 10,
636     EnumCount   = 10,
637 };
638 
639 class ImageHelper final : public CommandGraphResource
640 {
641   public:
642     ImageHelper();
643     ImageHelper(ImageHelper &&other);
644     ~ImageHelper() override;
645 
646     void initStagingBuffer(RendererVk *renderer,
647                            const vk::Format &format,
648                            VkBufferUsageFlags usageFlags,
649                            size_t initialSize);
650 
651     angle::Result init(Context *context,
652                        gl::TextureType textureType,
653                        const VkExtent3D &extents,
654                        const Format &format,
655                        GLint samples,
656                        VkImageUsageFlags usage,
657                        uint32_t mipLevels,
658                        uint32_t layerCount);
659     angle::Result initExternal(Context *context,
660                                gl::TextureType textureType,
661                                const VkExtent3D &extents,
662                                const Format &format,
663                                GLint samples,
664                                VkImageUsageFlags usage,
665                                ImageLayout initialLayout,
666                                const void *externalImageCreateInfo,
667                                uint32_t mipLevels,
668                                uint32_t layerCount);
669     angle::Result initMemory(Context *context,
670                              const MemoryProperties &memoryProperties,
671                              VkMemoryPropertyFlags flags);
672     angle::Result initExternalMemory(Context *context,
673                                      const MemoryProperties &memoryProperties,
674                                      const VkMemoryRequirements &memoryRequirements,
675                                      const void *extraAllocationInfo,
676                                      uint32_t currentQueueFamilyIndex,
677                                      VkMemoryPropertyFlags flags);
678     angle::Result initLayerImageView(Context *context,
679                                      gl::TextureType textureType,
680                                      VkImageAspectFlags aspectMask,
681                                      const gl::SwizzleState &swizzleMap,
682                                      ImageView *imageViewOut,
683                                      uint32_t baseMipLevel,
684                                      uint32_t levelCount,
685                                      uint32_t baseArrayLayer,
686                                      uint32_t layerCount);
687     angle::Result initImageView(Context *context,
688                                 gl::TextureType textureType,
689                                 VkImageAspectFlags aspectMask,
690                                 const gl::SwizzleState &swizzleMap,
691                                 ImageView *imageViewOut,
692                                 uint32_t baseMipLevel,
693                                 uint32_t levelCount);
694     // Create a 2D[Array] for staging purposes.  Used by:
695     //
696     // - TextureVk::copySubImageImplWithDraw
697     // - FramebufferVk::readPixelsImpl
698     //
699     angle::Result init2DStaging(Context *context,
700                                 const MemoryProperties &memoryProperties,
701                                 const gl::Extents &glExtents,
702                                 const Format &format,
703                                 VkImageUsageFlags usage,
704                                 uint32_t layerCount);
705 
706     void releaseImage(ContextVk *contextVk);
707     void releaseImage(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
708 
709     void releaseStagingBuffer(ContextVk *contextVk);
710     void releaseStagingBuffer(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
711 
valid()712     bool valid() const { return mImage.valid(); }
713 
714     VkImageAspectFlags getAspectFlags() const;
715     void destroy(VkDevice device);
716     void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue);
717 
718     void init2DWeakReference(VkImage handle,
719                              const gl::Extents &glExtents,
720                              const Format &format,
721                              GLint samples);
722     void resetImageWeakReference();
723 
getImage()724     const Image &getImage() const { return mImage; }
getDeviceMemory()725     const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
726 
getExtents()727     const VkExtent3D &getExtents() const { return mExtents; }
getLayerCount()728     uint32_t getLayerCount() const { return mLayerCount; }
getLevelCount()729     uint32_t getLevelCount() const { return mLevelCount; }
getFormat()730     const Format &getFormat() const { return *mFormat; }
getSamples()731     GLint getSamples() const { return mSamples; }
732 
733     VkImageLayout getCurrentLayout() const;
734 
735     // Helper function to calculate the extents of a render target created for a certain mip of the
736     // image.
737     gl::Extents getLevelExtents2D(uint32_t level) const;
738 
739     // Clear either color or depth/stencil based on image format.
740     void clear(const VkClearValue &value,
741                uint32_t mipLevel,
742                uint32_t baseArrayLayer,
743                uint32_t layerCount,
744                vk::CommandBuffer *commandBuffer);
745 
746     gl::Extents getSize(const gl::ImageIndex &index) const;
747 
748     static void Copy(ImageHelper *srcImage,
749                      ImageHelper *dstImage,
750                      const gl::Offset &srcOffset,
751                      const gl::Offset &dstOffset,
752                      const gl::Extents &copySize,
753                      const VkImageSubresourceLayers &srcSubresources,
754                      const VkImageSubresourceLayers &dstSubresources,
755                      vk::CommandBuffer *commandBuffer);
756 
757     angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
758 
759     // Resolve this image into a destination image.  This image should be in the TransferSrc layout.
760     // The destination image is automatically transitioned into TransferDst.
761     void resolve(ImageHelper *dest, const VkImageResolve &region, vk::CommandBuffer *commandBuffer);
762 
763     // Data staging
764     void removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index);
765 
766     angle::Result stageSubresourceUpdate(ContextVk *contextVk,
767                                          const gl::ImageIndex &index,
768                                          const gl::Extents &glExtents,
769                                          const gl::Offset &offset,
770                                          const gl::InternalFormat &formatInfo,
771                                          const gl::PixelUnpackState &unpack,
772                                          GLenum type,
773                                          const uint8_t *pixels,
774                                          const vk::Format &vkFormat);
775 
776     angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk,
777                                                    size_t allocationSize,
778                                                    const gl::ImageIndex &imageIndex,
779                                                    const gl::Extents &glExtents,
780                                                    const gl::Offset &offset,
781                                                    uint8_t **destData);
782 
783     angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context,
784                                                         const gl::ImageIndex &index,
785                                                         const gl::Rectangle &sourceArea,
786                                                         const gl::Offset &dstOffset,
787                                                         const gl::Extents &dstExtent,
788                                                         const gl::InternalFormat &formatInfo,
789                                                         FramebufferVk *framebufferVk);
790 
791     void stageSubresourceUpdateFromImage(vk::ImageHelper *image,
792                                          const gl::ImageIndex &index,
793                                          const gl::Offset &destOffset,
794                                          const gl::Extents &glExtents,
795                                          const VkImageType imageType);
796 
797     // Stage a clear operation to a clear value based on WebGL requirements.
798     void stageSubresourceRobustClear(const gl::ImageIndex &index, const angle::Format &format);
799 
800     // Stage a clear operation to a clear value that initializes emulated channels to the desired
801     // values.
802     void stageSubresourceEmulatedClear(const gl::ImageIndex &index, const angle::Format &format);
803 
804     // If the image has emulated channels, we clear them once so as not to leave garbage on those
805     // channels.
806     void stageClearIfEmulatedFormat(const gl::ImageIndex &index, const Format &format);
807 
808     // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
809     // dst.
810     angle::Result allocateStagingMemory(ContextVk *contextVk,
811                                         size_t sizeInBytes,
812                                         uint8_t **ptrOut,
813                                         VkBuffer *handleOut,
814                                         VkDeviceSize *offsetOut,
815                                         bool *newBufferAllocatedOut);
816 
817     // Flushes staged updates to a range of levels and layers from start to (but not including) end.
818     // Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited
819     // layers may also be updated.
820     angle::Result flushStagedUpdates(ContextVk *contextVk,
821                                      uint32_t levelStart,
822                                      uint32_t levelEnd,
823                                      uint32_t layerStart,
824                                      uint32_t layerEnd,
825                                      vk::CommandBuffer *commandBuffer);
826     // Creates a command buffer and flushes all staged updates.  This is used for one-time
827     // initialization of resources that we don't expect to accumulate further staged updates, such
828     // as with renderbuffers or surface images.
829     angle::Result flushAllStagedUpdates(ContextVk *contextVk);
830 
hasStagedUpdates()831     bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); }
832 
833     // changeLayout automatically skips the layout change if it's unnecessary.  This function can be
834     // used to prevent creating a command graph node and subsequently a command buffer for the sole
835     // purpose of performing a transition (which may then not be issued).
836     bool isLayoutChangeNecessary(ImageLayout newLayout) const;
837 
838     void changeLayout(VkImageAspectFlags aspectMask,
839                       ImageLayout newLayout,
840                       vk::CommandBuffer *commandBuffer);
841 
isQueueChangeNeccesary(uint32_t newQueueFamilyIndex)842     bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
843     {
844         return mCurrentQueueFamilyIndex != newQueueFamilyIndex;
845     }
846 
847     void changeLayoutAndQueue(VkImageAspectFlags aspectMask,
848                               ImageLayout newLayout,
849                               uint32_t newQueueFamilyIndex,
850                               vk::CommandBuffer *commandBuffer);
851 
852   private:
853     void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
854                                    ImageLayout newLayout,
855                                    uint32_t newQueueFamilyIndex,
856                                    vk::CommandBuffer *commandBuffer);
857 
858     void stageSubresourceClear(const gl::ImageIndex &index,
859                                const angle::Format &format,
860                                const VkClearColorValue &colorValue,
861                                const VkClearDepthStencilValue &depthStencilValue);
862 
863     void clearColor(const VkClearColorValue &color,
864                     uint32_t baseMipLevel,
865                     uint32_t levelCount,
866                     uint32_t baseArrayLayer,
867                     uint32_t layerCount,
868                     vk::CommandBuffer *commandBuffer);
869 
870     void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
871                            VkImageAspectFlags clearAspectFlags,
872                            const VkClearDepthStencilValue &depthStencil,
873                            uint32_t baseMipLevel,
874                            uint32_t levelCount,
875                            uint32_t baseArrayLayer,
876                            uint32_t layerCount,
877                            vk::CommandBuffer *commandBuffer);
878 
879     struct SubresourceUpdate
880     {
881         SubresourceUpdate();
882         SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy &copyRegion);
883         SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy &copyRegion);
884         SubresourceUpdate(const VkClearValue &clearValue, const gl::ImageIndex &imageIndex);
885         SubresourceUpdate(const SubresourceUpdate &other);
886 
887         void release(ContextVk *contextVk);
888         void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
889 
dstSubresourceSubresourceUpdate890         const VkImageSubresourceLayers &dstSubresource() const
891         {
892             ASSERT(updateSource == UpdateSource::Buffer || updateSource == UpdateSource::Image);
893             return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource
894                                                         : image.copyRegion.dstSubresource;
895         }
896         bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const;
897 
898         enum class UpdateSource
899         {
900             Clear,
901             Buffer,
902             Image,
903         };
904         struct ClearUpdate
905         {
906             VkClearValue value;
907             uint32_t levelIndex;
908             uint32_t layerIndex;
909             uint32_t layerCount;
910         };
911         struct BufferUpdate
912         {
913             VkBuffer bufferHandle;
914             VkBufferImageCopy copyRegion;
915         };
916         struct ImageUpdate
917         {
918             vk::ImageHelper *image;
919             VkImageCopy copyRegion;
920         };
921 
922         UpdateSource updateSource;
923         union
924         {
925             ClearUpdate clear;
926             BufferUpdate buffer;
927             ImageUpdate image;
928         };
929     };
930 
931     // Vulkan objects.
932     Image mImage;
933     DeviceMemory mDeviceMemory;
934 
935     // Image properties.
936     VkExtent3D mExtents;
937     const Format *mFormat;
938     GLint mSamples;
939 
940     // Current state.
941     ImageLayout mCurrentLayout;
942     uint32_t mCurrentQueueFamilyIndex;
943 
944     // Cached properties.
945     uint32_t mLayerCount;
946     uint32_t mLevelCount;
947 
948     // Staging buffer
949     vk::DynamicBuffer mStagingBuffer;
950     std::vector<SubresourceUpdate> mSubresourceUpdates;
951 };
952 
953 class FramebufferHelper : public CommandGraphResource
954 {
955   public:
956     FramebufferHelper();
957     ~FramebufferHelper() override;
958 
959     angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo);
960     void release(ContextVk *contextVk);
961 
valid()962     bool valid() { return mFramebuffer.valid(); }
963 
getFramebuffer()964     const Framebuffer &getFramebuffer() const
965     {
966         ASSERT(mFramebuffer.valid());
967         return mFramebuffer;
968     }
969 
getFramebuffer()970     Framebuffer &getFramebuffer()
971     {
972         ASSERT(mFramebuffer.valid());
973         return mFramebuffer;
974     }
975 
976   private:
977     // Vulkan object.
978     Framebuffer mFramebuffer;
979 };
980 
981 // A special command graph resource to hold resource dependencies for dispatch calls.  It's the
982 // equivalent of FramebufferHelper, though it doesn't contain a Vulkan object.
983 class DispatchHelper : public CommandGraphResource
984 {
985   public:
986     DispatchHelper();
987     ~DispatchHelper() override;
988 };
989 
990 class ShaderProgramHelper : angle::NonCopyable
991 {
992   public:
993     ShaderProgramHelper();
994     ~ShaderProgramHelper();
995 
996     bool valid() const;
997     void destroy(VkDevice device);
998     void release(ContextVk *contextVk);
999 
isGraphicsProgram()1000     bool isGraphicsProgram() const
1001     {
1002         ASSERT(mShaders[gl::ShaderType::Vertex].valid() !=
1003                mShaders[gl::ShaderType::Compute].valid());
1004         return mShaders[gl::ShaderType::Vertex].valid();
1005     }
1006 
getShader(gl::ShaderType shaderType)1007     vk::ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); }
1008 
1009     void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader);
1010 
1011     // For getting a vk::Pipeline and from the pipeline cache.
getGraphicsPipeline(Context * context,RenderPassCache * renderPassCache,const PipelineCache & pipelineCache,Serial currentQueueSerial,const PipelineLayout & pipelineLayout,const GraphicsPipelineDesc & pipelineDesc,const gl::AttributesMask & activeAttribLocationsMask,const gl::ComponentTypeMask & programAttribsTypeMask,const vk::GraphicsPipelineDesc ** descPtrOut,PipelineHelper ** pipelineOut)1012     ANGLE_INLINE angle::Result getGraphicsPipeline(
1013         Context *context,
1014         RenderPassCache *renderPassCache,
1015         const PipelineCache &pipelineCache,
1016         Serial currentQueueSerial,
1017         const PipelineLayout &pipelineLayout,
1018         const GraphicsPipelineDesc &pipelineDesc,
1019         const gl::AttributesMask &activeAttribLocationsMask,
1020         const gl::ComponentTypeMask &programAttribsTypeMask,
1021         const vk::GraphicsPipelineDesc **descPtrOut,
1022         PipelineHelper **pipelineOut)
1023     {
1024         // Pull in a compatible RenderPass.
1025         vk::RenderPass *compatibleRenderPass = nullptr;
1026         ANGLE_TRY(renderPassCache->getCompatibleRenderPass(
1027             context, currentQueueSerial, pipelineDesc.getRenderPassDesc(), &compatibleRenderPass));
1028 
1029         ShaderModule *vertexShader   = &mShaders[gl::ShaderType::Vertex].get().get();
1030         ShaderModule *fragmentShader = mShaders[gl::ShaderType::Fragment].valid()
1031                                            ? &mShaders[gl::ShaderType::Fragment].get().get()
1032                                            : nullptr;
1033 
1034         return mGraphicsPipelines.getPipeline(context, pipelineCache, *compatibleRenderPass,
1035                                               pipelineLayout, activeAttribLocationsMask,
1036                                               programAttribsTypeMask, vertexShader, fragmentShader,
1037                                               pipelineDesc, descPtrOut, pipelineOut);
1038     }
1039 
1040     angle::Result getComputePipeline(Context *context,
1041                                      const PipelineLayout &pipelineLayout,
1042                                      PipelineAndSerial **pipelineOut);
1043 
1044   private:
1045     gl::ShaderMap<BindingPointer<ShaderAndSerial>> mShaders;
1046     GraphicsPipelineCache mGraphicsPipelines;
1047 
1048     // We should probably use PipelineHelper here so we can remove PipelineAndSerial.
1049     PipelineAndSerial mComputePipeline;
1050 };
1051 }  // namespace vk
1052 }  // namespace rx
1053 
1054 #endif  // LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_
1055