• 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 "common/MemoryBuffer.h"
13 #include "libANGLE/renderer/vulkan/ResourceVk.h"
14 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
15 
16 namespace gl
17 {
18 class ImageIndex;
19 }  // namespace gl
20 
21 namespace rx
22 {
23 namespace vk
24 {
25 constexpr VkBufferUsageFlags kVertexBufferUsageFlags =
26     VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
27 constexpr VkBufferUsageFlags kIndexBufferUsageFlags =
28     VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
29 constexpr VkBufferUsageFlags kIndirectBufferUsageFlags =
30     VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
31 constexpr size_t kVertexBufferAlignment   = 4;
32 constexpr size_t kIndexBufferAlignment    = 4;
33 constexpr size_t kIndirectBufferAlignment = 4;
34 
35 constexpr VkBufferUsageFlags kStagingBufferFlags =
36     VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
37 constexpr size_t kStagingBufferSize = 1024 * 16;
38 
39 using StagingBufferOffsetArray = std::array<VkDeviceSize, 2>;
40 
41 struct TextureUnit final
42 {
43     TextureVk *texture;
44     SamplerVk *sampler;
45 };
46 
47 // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer,
48 // you will always write to a previously unused portion. After a series of writes, you must flush
49 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will
50 // last as long or longer than each prior allocation.
51 //
52 // Dynamic buffers are used to implement a variety of data streaming operations in Vulkan, such
53 // as for immediate vertex array and element array data, uniform updates, and other dynamic data.
54 //
55 // Internally dynamic buffers keep a collection of VkBuffers. When we write past the end of a
56 // currently active VkBuffer we keep it until it is no longer in use. We then mark it available
57 // for future allocations in a free list.
58 class BufferHelper;
59 class DynamicBuffer : angle::NonCopyable
60 {
61   public:
62     DynamicBuffer();
63     DynamicBuffer(DynamicBuffer &&other);
64     ~DynamicBuffer();
65 
66     // Init is called after the buffer creation so that the alignment can be specified later.
67     void init(RendererVk *renderer,
68               VkBufferUsageFlags usage,
69               size_t alignment,
70               size_t initialSize,
71               bool hostVisible);
72 
73     // This call will allocate a new region at the end of the buffer. It internally may trigger
74     // a new buffer to be created (which is returned in the optional parameter
75     // `newBufferAllocatedOut`).  The new region will be in the returned buffer at given offset. If
76     // a memory pointer is given, the buffer will be automatically map()ed.
77     angle::Result allocate(ContextVk *contextVk,
78                            size_t sizeInBytes,
79                            uint8_t **ptrOut,
80                            VkBuffer *bufferOut,
81                            VkDeviceSize *offsetOut,
82                            bool *newBufferAllocatedOut);
83 
84     // After a sequence of writes, call flush to ensure the data is visible to the device.
85     angle::Result flush(ContextVk *contextVk);
86 
87     // After a sequence of writes, call invalidate to ensure the data is visible to the host.
88     angle::Result invalidate(ContextVk *contextVk);
89 
90     // This releases resources when they might currently be in use.
91     void release(RendererVk *renderer);
92 
93     // This releases all the buffers that have been allocated since this was last called.
94     void releaseInFlightBuffers(ContextVk *contextVk);
95 
96     // This frees resources immediately.
97     void destroy(RendererVk *renderer);
98 
getCurrentBuffer()99     BufferHelper *getCurrentBuffer() { return mBuffer; }
100 
101     void updateAlignment(RendererVk *renderer, size_t alignment);
102 
103     // For testing only!
104     void setMinimumSizeForTesting(size_t minSize);
105 
106   private:
107     void reset();
108     angle::Result allocateNewBuffer(ContextVk *contextVk);
109     void releaseBufferListToRenderer(RendererVk *renderer, std::vector<BufferHelper *> *buffers);
110     void destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers);
111 
112     VkBufferUsageFlags mUsage;
113     bool mHostVisible;
114     size_t mInitialSize;
115     BufferHelper *mBuffer;
116     uint32_t mNextAllocationOffset;
117     uint32_t mLastFlushOrInvalidateOffset;
118     size_t mSize;
119     size_t mAlignment;
120 
121     std::vector<BufferHelper *> mInFlightBuffers;
122     std::vector<BufferHelper *> mBufferFreeList;
123 };
124 
125 // Based off of the DynamicBuffer class, DynamicShadowBuffer provides
126 // a similar conceptually infinitely long buffer that will only be written
127 // to and read by the CPU. This can be used to provide CPU cached copies of
128 // GPU-read only buffers. The value add here is that when an app requests
129 // CPU access to a buffer we can fullfil such a request in O(1) time since
130 // we don't need to wait for GPU to be done with in-flight commands.
131 //
132 // The hidden cost here is that any operation that updates a buffer, either
133 // through a buffer sub data update or a buffer-to-buffer copy will have an
134 // additional overhead of having to update its CPU only buffer
135 class DynamicShadowBuffer : public angle::NonCopyable
136 {
137   public:
138     DynamicShadowBuffer();
139     DynamicShadowBuffer(DynamicShadowBuffer &&other);
140     ~DynamicShadowBuffer();
141 
142     // Initialize the DynamicShadowBuffer.
143     void init(size_t initialSize);
144 
145     // Returns whether this DynamicShadowBuffer is active
valid()146     ANGLE_INLINE bool valid() { return (mSize != 0); }
147 
148     // This call will actually allocate a new CPU only memory from the heap.
149     // The size can be different than the one specified during `init`.
150     angle::Result allocate(size_t sizeInBytes);
151 
updateData(const uint8_t * data,size_t size,size_t offset)152     ANGLE_INLINE void updateData(const uint8_t *data, size_t size, size_t offset)
153     {
154         ASSERT(!mBuffer.empty());
155         // Memcopy data into the buffer
156         memcpy((mBuffer.data() + offset), data, size);
157     }
158 
159     // Map the CPU only buffer and return the pointer. We map the entire buffer for now.
map(size_t offset,void ** mapPtr)160     ANGLE_INLINE void map(size_t offset, void **mapPtr)
161     {
162         ASSERT(mapPtr);
163         ASSERT(!mBuffer.empty());
164         *mapPtr = mBuffer.data() + offset;
165     }
166 
167     // Unmap the CPU only buffer, NOOP for now
unmap()168     ANGLE_INLINE void unmap() {}
169 
170     // This releases resources when they might currently be in use.
171     void release();
172 
173     // This frees resources immediately.
174     void destroy(VkDevice device);
175 
getCurrentBuffer()176     ANGLE_INLINE uint8_t *getCurrentBuffer()
177     {
178         ASSERT(!mBuffer.empty());
179         return mBuffer.data();
180     }
181 
getCurrentBuffer()182     ANGLE_INLINE const uint8_t *getCurrentBuffer() const
183     {
184         ASSERT(!mBuffer.empty());
185         return mBuffer.data();
186     }
187 
188   private:
189     void reset();
190 
191     size_t mInitialSize;
192     size_t mSize;
193     angle::MemoryBuffer mBuffer;
194 };
195 
196 // Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we
197 // allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded
198 // pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must
199 // use set zero and combined Image Samplers must use set 1. We conservatively count each new set
200 // using the maximum number of descriptor sets and buffers with each allocation. Currently: 2
201 // (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers.
202 
203 // Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool.
204 // Can be used to share descriptor pools between multiple ProgramVks and the ContextVk.
205 class DescriptorPoolHelper
206 {
207   public:
208     DescriptorPoolHelper();
209     ~DescriptorPoolHelper();
210 
valid()211     bool valid() { return mDescriptorPool.valid(); }
212 
213     bool hasCapacity(uint32_t descriptorSetCount) const;
214     angle::Result init(Context *context,
215                        const std::vector<VkDescriptorPoolSize> &poolSizes,
216                        uint32_t maxSets);
217     void destroy(VkDevice device);
218     void release(ContextVk *contextVk);
219 
220     angle::Result allocateSets(ContextVk *contextVk,
221                                const VkDescriptorSetLayout *descriptorSetLayout,
222                                uint32_t descriptorSetCount,
223                                VkDescriptorSet *descriptorSetsOut);
224 
updateSerial(Serial serial)225     void updateSerial(Serial serial) { mMostRecentSerial = serial; }
226 
getSerial()227     Serial getSerial() const { return mMostRecentSerial; }
228 
229   private:
230     uint32_t mFreeDescriptorSets;
231     DescriptorPool mDescriptorPool;
232     Serial mMostRecentSerial;
233 };
234 
235 using RefCountedDescriptorPoolHelper  = RefCounted<DescriptorPoolHelper>;
236 using RefCountedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>;
237 
238 class DynamicDescriptorPool final : angle::NonCopyable
239 {
240   public:
241     DynamicDescriptorPool();
242     ~DynamicDescriptorPool();
243 
244     // The DynamicDescriptorPool only handles one pool size at this time.
245     // Note that setSizes[i].descriptorCount is expected to be the number of descriptors in
246     // an individual set.  The pool size will be calculated accordingly.
247     angle::Result init(ContextVk *contextVk,
248                        const VkDescriptorPoolSize *setSizes,
249                        uint32_t setSizeCount);
250     void destroy(VkDevice device);
251     void release(ContextVk *contextVk);
252 
253     // We use the descriptor type to help count the number of free sets.
254     // 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)255     ANGLE_INLINE angle::Result allocateSets(ContextVk *contextVk,
256                                             const VkDescriptorSetLayout *descriptorSetLayout,
257                                             uint32_t descriptorSetCount,
258                                             RefCountedDescriptorPoolBinding *bindingOut,
259                                             VkDescriptorSet *descriptorSetsOut)
260     {
261         bool ignoreNewPoolAllocated;
262         return allocateSetsAndGetInfo(contextVk, descriptorSetLayout, descriptorSetCount,
263                                       bindingOut, descriptorSetsOut, &ignoreNewPoolAllocated);
264     }
265 
266     // We use the descriptor type to help count the number of free sets.
267     // By convention, sets are indexed according to the constants in vk_cache_utils.h.
268     angle::Result allocateSetsAndGetInfo(ContextVk *contextVk,
269                                          const VkDescriptorSetLayout *descriptorSetLayout,
270                                          uint32_t descriptorSetCount,
271                                          RefCountedDescriptorPoolBinding *bindingOut,
272                                          VkDescriptorSet *descriptorSetsOut,
273                                          bool *newPoolAllocatedOut);
274 
275     // For testing only!
276     void setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool);
277 
278   private:
279     angle::Result allocateNewPool(ContextVk *contextVk);
280 
281     uint32_t mMaxSetsPerPool;
282     size_t mCurrentPoolIndex;
283     std::vector<RefCountedDescriptorPoolHelper *> mDescriptorPools;
284     std::vector<VkDescriptorPoolSize> mPoolSizes;
285 };
286 
287 template <typename Pool>
288 class DynamicallyGrowingPool : angle::NonCopyable
289 {
290   public:
291     DynamicallyGrowingPool();
292     virtual ~DynamicallyGrowingPool();
293 
isValid()294     bool isValid() { return mPoolSize > 0; }
295 
296   protected:
297     angle::Result initEntryPool(Context *contextVk, uint32_t poolSize);
298     void destroyEntryPool();
299 
300     // Checks to see if any pool is already free, in which case it sets it as current pool and
301     // returns true.
302     bool findFreeEntryPool(ContextVk *contextVk);
303 
304     // Allocates a new entry and initializes it with the given pool.
305     angle::Result allocateNewEntryPool(ContextVk *contextVk, Pool &&pool);
306 
307     // Called by the implementation whenever an entry is freed.
308     void onEntryFreed(ContextVk *contextVk, size_t poolIndex);
309 
310     // The pool size, to know when a pool is completely freed.
311     uint32_t mPoolSize;
312 
313     std::vector<Pool> mPools;
314 
315     struct PoolStats
316     {
317         // A count corresponding to each pool indicating how many of its allocated entries
318         // have been freed. Once that value reaches mPoolSize for each pool, that pool is considered
319         // free and reusable.  While keeping a bitset would allow allocation of each index, the
320         // slight runtime overhead of finding free indices is not worth the slight memory overhead
321         // of creating new pools when unnecessary.
322         uint32_t freedCount;
323         // The serial of the renderer is stored on each object free to make sure no
324         // new allocations are made from the pool until it's not in use.
325         Serial serial;
326     };
327     std::vector<PoolStats> mPoolStats;
328 
329     // Index into mPools indicating pool we are currently allocating from.
330     size_t mCurrentPool;
331     // Index inside mPools[mCurrentPool] indicating which index can be allocated next.
332     uint32_t mCurrentFreeEntry;
333 };
334 
335 // DynamicQueryPool allocates indices out of QueryPool as needed.  Once a QueryPool is exhausted,
336 // another is created.  The query pools live permanently, but are recycled as indices get freed.
337 
338 // These are arbitrary default sizes for query pools.
339 constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64;
340 constexpr uint32_t kDefaultTimestampQueryPoolSize = 64;
341 
342 class QueryHelper;
343 
344 class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool>
345 {
346   public:
347     DynamicQueryPool();
348     ~DynamicQueryPool() override;
349 
350     angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize);
351     void destroy(VkDevice device);
352 
353     angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut);
354     void freeQuery(ContextVk *contextVk, QueryHelper *query);
355 
getQueryPool(size_t index)356     const QueryPool &getQueryPool(size_t index) const { return mPools[index]; }
357 
358   private:
359     angle::Result allocateNewPool(ContextVk *contextVk);
360 
361     // Information required to create new query pools
362     VkQueryType mQueryType;
363 };
364 
365 // Queries in vulkan are identified by the query pool and an index for a query within that pool.
366 // Unlike other pools, such as descriptor pools where an allocation returns an independent object
367 // from the pool, the query allocations are not done through a Vulkan function and are only an
368 // integer index.
369 //
370 // Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools
371 // of a fixed size as needed and allocates indices within those pools.
372 //
373 // The QueryHelper class below keeps the pool and index pair together.
374 class QueryHelper final
375 {
376   public:
377     QueryHelper();
378     ~QueryHelper();
379 
380     void init(const DynamicQueryPool *dynamicQueryPool,
381               const size_t queryPoolIndex,
382               uint32_t query);
383     void deinit();
384 
valid()385     bool valid() const { return mDynamicQueryPool != nullptr; }
386 
387     angle::Result beginQuery(ContextVk *contextVk);
388     angle::Result endQuery(ContextVk *contextVk);
389 
390     // for occlusion query
391     void beginOcclusionQuery(ContextVk *contextVk,
392                              PrimaryCommandBuffer *primaryCommands,
393                              CommandBuffer *renderPassCommandBuffer);
394     void endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
395 
396     angle::Result flushAndWriteTimestamp(ContextVk *contextVk);
397     void writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary);
398 
getStoredQueueSerial()399     Serial getStoredQueueSerial() { return mMostRecentSerial; }
400     bool hasPendingWork(ContextVk *contextVk);
401 
402     angle::Result getUint64ResultNonBlocking(ContextVk *contextVk,
403                                              uint64_t *resultOut,
404                                              bool *availableOut);
405     angle::Result getUint64Result(ContextVk *contextVk, uint64_t *resultOut);
406 
407   private:
408     friend class DynamicQueryPool;
getQueryPool()409     const QueryPool &getQueryPool() const
410     {
411         ASSERT(valid());
412         return mDynamicQueryPool->getQueryPool(mQueryPoolIndex);
413     }
414 
415     const DynamicQueryPool *mDynamicQueryPool;
416     size_t mQueryPoolIndex;
417     uint32_t mQuery;
418     Serial mMostRecentSerial;
419 };
420 
421 // DynamicSemaphorePool allocates semaphores as needed.  It uses a std::vector
422 // as a pool to allocate many semaphores at once.  The pools live permanently,
423 // but are recycled as semaphores get freed.
424 
425 // These are arbitrary default sizes for semaphore pools.
426 constexpr uint32_t kDefaultSemaphorePoolSize = 64;
427 
428 class SemaphoreHelper;
429 
430 class DynamicSemaphorePool final : public DynamicallyGrowingPool<std::vector<Semaphore>>
431 {
432   public:
433     DynamicSemaphorePool();
434     ~DynamicSemaphorePool() override;
435 
436     angle::Result init(ContextVk *contextVk, uint32_t poolSize);
437     void destroy(VkDevice device);
438 
isValid()439     bool isValid() { return mPoolSize > 0; }
440 
441     // autoFree can be used to allocate a semaphore that's expected to be freed at the end of the
442     // frame.  This renders freeSemaphore unnecessary and saves an eventual search.
443     angle::Result allocateSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphoreOut);
444     void freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore);
445 
446   private:
447     angle::Result allocateNewPool(ContextVk *contextVk);
448 };
449 
450 // Semaphores that are allocated from the semaphore pool are encapsulated in a helper object,
451 // keeping track of where in the pool they are allocated from.
452 class SemaphoreHelper final : angle::NonCopyable
453 {
454   public:
455     SemaphoreHelper();
456     ~SemaphoreHelper();
457 
458     SemaphoreHelper(SemaphoreHelper &&other);
459     SemaphoreHelper &operator=(SemaphoreHelper &&other);
460 
461     void init(const size_t semaphorePoolIndex, const Semaphore *semaphore);
462     void deinit();
463 
getSemaphore()464     const Semaphore *getSemaphore() const { return mSemaphore; }
465 
466     // Used only by DynamicSemaphorePool.
getSemaphorePoolIndex()467     size_t getSemaphorePoolIndex() const { return mSemaphorePoolIndex; }
468 
469   private:
470     size_t mSemaphorePoolIndex;
471     const Semaphore *mSemaphore;
472 };
473 
474 // This class' responsibility is to create index buffers needed to support line loops in Vulkan.
475 // In the setup phase of drawing, the createIndexBuffer method should be called with the
476 // current draw call parameters. If an element array buffer is bound for an indexed draw, use
477 // createIndexBufferFromElementArrayBuffer.
478 //
479 // If the user wants to draw a loop between [v1, v2, v3], we will create an indexed buffer with
480 // these indexes: [0, 1, 2, 3, 0] to emulate the loop.
481 class LineLoopHelper final : angle::NonCopyable
482 {
483   public:
484     LineLoopHelper(RendererVk *renderer);
485     ~LineLoopHelper();
486 
487     angle::Result getIndexBufferForDrawArrays(ContextVk *contextVk,
488                                               uint32_t clampedVertexCount,
489                                               GLint firstVertex,
490                                               BufferHelper **bufferOut,
491                                               VkDeviceSize *offsetOut);
492 
493     angle::Result getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
494                                                       BufferVk *elementArrayBufferVk,
495                                                       gl::DrawElementsType glIndexType,
496                                                       int indexCount,
497                                                       intptr_t elementArrayOffset,
498                                                       BufferHelper **bufferOut,
499                                                       VkDeviceSize *bufferOffsetOut,
500                                                       uint32_t *indexCountOut);
501 
502     angle::Result streamIndices(ContextVk *contextVk,
503                                 gl::DrawElementsType glIndexType,
504                                 GLsizei indexCount,
505                                 const uint8_t *srcPtr,
506                                 BufferHelper **bufferOut,
507                                 VkDeviceSize *bufferOffsetOut,
508                                 uint32_t *indexCountOut);
509 
510     angle::Result streamIndicesIndirect(ContextVk *contextVk,
511                                         gl::DrawElementsType glIndexType,
512                                         BufferHelper *indexBuffer,
513                                         BufferHelper *indirectBuffer,
514                                         VkDeviceSize indirectBufferOffset,
515                                         BufferHelper **indexBufferOut,
516                                         VkDeviceSize *indexBufferOffsetOut,
517                                         BufferHelper **indirectBufferOut,
518                                         VkDeviceSize *indirectBufferOffsetOut);
519 
520     angle::Result streamArrayIndirect(ContextVk *contextVk,
521                                       size_t vertexCount,
522                                       BufferHelper *arrayIndirectBuffer,
523                                       VkDeviceSize arrayIndirectBufferOffset,
524                                       BufferHelper **indexBufferOut,
525                                       VkDeviceSize *indexBufferOffsetOut,
526                                       BufferHelper **indexIndirectBufferOut,
527                                       VkDeviceSize *indexIndirectBufferOffsetOut);
528 
529     void release(ContextVk *contextVk);
530     void destroy(RendererVk *renderer);
531 
532     static void Draw(uint32_t count, uint32_t baseVertex, CommandBuffer *commandBuffer);
533 
534   private:
535     DynamicBuffer mDynamicIndexBuffer;
536     DynamicBuffer mDynamicIndirectBuffer;
537 };
538 
539 class FramebufferHelper;
540 
541 class BufferHelper final : public Resource
542 {
543   public:
544     BufferHelper();
545     ~BufferHelper() override;
546 
547     angle::Result init(ContextVk *contextVk,
548                        const VkBufferCreateInfo &createInfo,
549                        VkMemoryPropertyFlags memoryPropertyFlags);
550     void destroy(RendererVk *renderer);
551 
552     void release(RendererVk *renderer);
553 
valid()554     bool valid() const { return mBuffer.valid(); }
getBuffer()555     const Buffer &getBuffer() const { return mBuffer; }
getSize()556     VkDeviceSize getSize() const { return mSize; }
isHostVisible()557     bool isHostVisible() const
558     {
559         return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
560     }
561 
562     // Set write access mask when the buffer is modified externally, e.g. by host.  There is no
563     // graph resource to create a dependency to.
onExternalWrite(VkAccessFlags writeAccessType)564     void onExternalWrite(VkAccessFlags writeAccessType) { mCurrentWriteAccess |= writeAccessType; }
565 
566     // Also implicitly sets up the correct barriers.
567     angle::Result copyFromBuffer(ContextVk *contextVk,
568                                  BufferHelper *srcBuffer,
569                                  VkAccessFlags bufferAccessType,
570                                  const VkBufferCopy &copyRegion);
571 
572     // Note: currently only one view is allowed.  If needs be, multiple views can be created
573     // based on format.
574     angle::Result initBufferView(ContextVk *contextVk, const Format &format);
575 
getBufferView()576     const BufferView &getBufferView() const
577     {
578         ASSERT(mBufferView.valid());
579         return mBufferView;
580     }
581 
getViewFormat()582     const Format &getViewFormat() const
583     {
584         ASSERT(mViewFormat);
585         return *mViewFormat;
586     }
587 
map(ContextVk * contextVk,uint8_t ** ptrOut)588     angle::Result map(ContextVk *contextVk, uint8_t **ptrOut)
589     {
590         if (!mMappedMemory)
591         {
592             ANGLE_TRY(mapImpl(contextVk));
593         }
594         *ptrOut = mMappedMemory;
595         return angle::Result::Continue;
596     }
597 
mapWithOffset(ContextVk * contextVk,uint8_t ** ptrOut,size_t offset)598     angle::Result mapWithOffset(ContextVk *contextVk, uint8_t **ptrOut, size_t offset)
599     {
600         uint8_t *mapBufPointer;
601         ANGLE_TRY(map(contextVk, &mapBufPointer));
602         *ptrOut = mapBufPointer + offset;
603         return angle::Result::Continue;
604     }
605 
606     void unmap(RendererVk *renderer);
607 
608     // After a sequence of writes, call flush to ensure the data is visible to the device.
609     angle::Result flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
610 
611     // After a sequence of writes, call invalidate to ensure the data is visible to the host.
612     angle::Result invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
613 
614     void changeQueue(uint32_t newQueueFamilyIndex, CommandBuffer *commandBuffer);
615 
616     // Currently always returns false. Should be smarter about accumulation.
617     bool canAccumulateRead(ContextVk *contextVk, VkAccessFlags readAccessType);
618     bool canAccumulateWrite(ContextVk *contextVk, VkAccessFlags writeAccessType);
619 
620     void updateReadBarrier(VkAccessFlags readAccessType,
621                            VkAccessFlags *barrierSrcOut,
622                            VkAccessFlags *barrierDstOut);
623 
624     void updateWriteBarrier(VkAccessFlags writeAccessType,
625                             VkAccessFlags *barrierSrcOut,
626                             VkAccessFlags *barrierDstOut);
627 
628   private:
629     angle::Result mapImpl(ContextVk *contextVk);
needsOnReadBarrier(VkAccessFlags readAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)630     bool needsOnReadBarrier(VkAccessFlags readAccessType,
631                             VkAccessFlags *barrierSrcOut,
632                             VkAccessFlags *barrierDstOut)
633     {
634         bool needsBarrier =
635             mCurrentWriteAccess != 0 && (mCurrentReadAccess & readAccessType) != readAccessType;
636 
637         *barrierSrcOut = mCurrentWriteAccess;
638         *barrierDstOut = readAccessType;
639 
640         mCurrentReadAccess |= readAccessType;
641         return needsBarrier;
642     }
643     bool needsOnWriteBarrier(VkAccessFlags writeAccessType,
644                              VkAccessFlags *barrierSrcOut,
645                              VkAccessFlags *barrierDstOut);
646 
647     angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size);
648 
649     // Vulkan objects.
650     Buffer mBuffer;
651     BufferView mBufferView;
652     Allocation mAllocation;
653 
654     // Cached properties.
655     VkMemoryPropertyFlags mMemoryPropertyFlags;
656     VkDeviceSize mSize;
657     uint8_t *mMappedMemory;
658     const Format *mViewFormat;
659     uint32_t mCurrentQueueFamilyIndex;
660 
661     // For memory barriers.
662     VkFlags mCurrentWriteAccess;
663     VkFlags mCurrentReadAccess;
664 };
665 
666 // Imagine an image going through a few layout transitions:
667 //
668 //           srcStage 1    dstStage 2          srcStage 2     dstStage 3
669 //  Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
670 //           srcAccess 1  dstAccess 2          srcAccess 2   dstAccess 3
671 //   \_________________  ___________________/
672 //                     \/
673 //               A transition
674 //
675 // Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and
676 // src/dst access masks.  At the moment we decide to transition the image to Layout 2 (i.e.
677 // Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the
678 // image.  To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2.
679 // Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition.
680 //
681 // That is, with the history kept, on every new transition we need 5 pieces of new information:
682 // layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future
683 // transition out from it.  Given the small number of possible combinations of these values, an
684 // enum is used were each value encapsulates these 5 pieces of information:
685 //
686 //                       +--------------------------------+
687 //           srcStage 1  | dstStage 2          srcStage 2 |   dstStage 3
688 //  Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
689 //           srcAccess 1 |dstAccess 2          srcAccess 2|  dstAccess 3
690 //                       +---------------  ---------------+
691 //                                       \/
692 //                                 One enum value
693 //
694 // Note that, while generally dstStage for the to-transition and srcStage for the from-transition
695 // are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively.
696 enum class ImageLayout
697 {
698     Undefined                   = 0,
699     ExternalPreInitialized      = 1,
700     ExternalShadersReadOnly     = 2,
701     ExternalShadersWrite        = 3,
702     TransferSrc                 = 4,
703     TransferDst                 = 5,
704     VertexShaderReadOnly        = 6,
705     VertexShaderWrite           = 7,
706     GeometryShaderReadOnly      = 8,
707     GeometryShaderWrite         = 9,
708     FragmentShaderReadOnly      = 10,
709     FragmentShaderWrite         = 11,
710     ComputeShaderReadOnly       = 12,
711     ComputeShaderWrite          = 13,
712     AllGraphicsShadersReadOnly  = 14,
713     AllGraphicsShadersReadWrite = 15,
714     ColorAttachment             = 16,
715     DepthStencilAttachment      = 17,
716     Present                     = 18,
717 
718     InvalidEnum = 19,
719     EnumCount   = 19,
720 };
721 
722 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout);
723 
724 class ImageHelper final : public Resource, public angle::Subject
725 {
726   public:
727     ImageHelper();
728     ImageHelper(ImageHelper &&other);
729     ~ImageHelper() override;
730 
731     void initStagingBuffer(RendererVk *renderer,
732                            const Format &format,
733                            VkBufferUsageFlags usageFlags,
734                            size_t initialSize);
735 
736     angle::Result init(Context *context,
737                        gl::TextureType textureType,
738                        const VkExtent3D &extents,
739                        const Format &format,
740                        GLint samples,
741                        VkImageUsageFlags usage,
742                        uint32_t baseLevel,
743                        uint32_t maxLevel,
744                        uint32_t mipLevels,
745                        uint32_t layerCount);
746     angle::Result initExternal(Context *context,
747                                gl::TextureType textureType,
748                                const VkExtent3D &extents,
749                                const Format &format,
750                                GLint samples,
751                                VkImageUsageFlags usage,
752                                ImageLayout initialLayout,
753                                const void *externalImageCreateInfo,
754                                uint32_t baseLevel,
755                                uint32_t maxLevel,
756                                uint32_t mipLevels,
757                                uint32_t layerCount);
758     angle::Result initMemory(Context *context,
759                              const MemoryProperties &memoryProperties,
760                              VkMemoryPropertyFlags flags);
761     angle::Result initExternalMemory(Context *context,
762                                      const MemoryProperties &memoryProperties,
763                                      const VkMemoryRequirements &memoryRequirements,
764                                      const void *extraAllocationInfo,
765                                      uint32_t currentQueueFamilyIndex,
766                                      VkMemoryPropertyFlags flags);
767     angle::Result initLayerImageView(Context *context,
768                                      gl::TextureType textureType,
769                                      VkImageAspectFlags aspectMask,
770                                      const gl::SwizzleState &swizzleMap,
771                                      ImageView *imageViewOut,
772                                      uint32_t baseMipLevel,
773                                      uint32_t levelCount,
774                                      uint32_t baseArrayLayer,
775                                      uint32_t layerCount) const;
776     angle::Result initImageView(Context *context,
777                                 gl::TextureType textureType,
778                                 VkImageAspectFlags aspectMask,
779                                 const gl::SwizzleState &swizzleMap,
780                                 ImageView *imageViewOut,
781                                 uint32_t baseMipLevel,
782                                 uint32_t levelCount);
783     // Create a 2D[Array] for staging purposes.  Used by:
784     //
785     // - TextureVk::copySubImageImplWithDraw
786     // - FramebufferVk::readPixelsImpl
787     //
788     angle::Result init2DStaging(Context *context,
789                                 const MemoryProperties &memoryProperties,
790                                 const gl::Extents &glExtents,
791                                 const Format &format,
792                                 VkImageUsageFlags usage,
793                                 uint32_t layerCount);
794 
795     void releaseImage(RendererVk *rendererVk);
796     void releaseStagingBuffer(RendererVk *renderer);
797 
valid()798     bool valid() const { return mImage.valid(); }
799 
800     VkImageAspectFlags getAspectFlags() const;
801     // True if image contains both depth & stencil aspects
802     bool isCombinedDepthStencilFormat() const;
803     void destroy(RendererVk *renderer);
release(RendererVk * renderer)804     void release(RendererVk *renderer) { destroy(renderer); }
805 
806     void init2DWeakReference(Context *context,
807                              VkImage handle,
808                              const gl::Extents &glExtents,
809                              const Format &format,
810                              GLint samples);
811     void resetImageWeakReference();
812 
getImage()813     const Image &getImage() const { return mImage; }
getDeviceMemory()814     const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
815 
getType()816     VkImageType getType() const { return mImageType; }
getExtents()817     const VkExtent3D &getExtents() const { return mExtents; }
getLayerCount()818     uint32_t getLayerCount() const { return mLayerCount; }
getLevelCount()819     uint32_t getLevelCount() const { return mLevelCount; }
getFormat()820     const Format &getFormat() const { return *mFormat; }
getSamples()821     GLint getSamples() const { return mSamples; }
822 
setCurrentImageLayout(ImageLayout newLayout)823     void setCurrentImageLayout(ImageLayout newLayout) { mCurrentLayout = newLayout; }
getCurrentImageLayout()824     ImageLayout getCurrentImageLayout() const { return mCurrentLayout; }
825     VkImageLayout getCurrentLayout() const;
826 
827     // Helper function to calculate the extents of a render target created for a certain mip of the
828     // image.
829     gl::Extents getLevelExtents2D(uint32_t level) const;
830 
831     // Clear either color or depth/stencil based on image format.
832     void clear(VkImageAspectFlags aspectFlags,
833                const VkClearValue &value,
834                uint32_t mipLevel,
835                uint32_t baseArrayLayer,
836                uint32_t layerCount,
837                CommandBuffer *commandBuffer);
838 
839     gl::Extents getSize(const gl::ImageIndex &index) const;
840 
841     // Return unique Serial for underlying image, first assigning it if it hasn't been set yet
842     Serial getAssignSerial(ContextVk *contextVk);
resetSerial()843     void resetSerial() { mSerial = rx::kZeroSerial; }
844 
845     static void Copy(ImageHelper *srcImage,
846                      ImageHelper *dstImage,
847                      const gl::Offset &srcOffset,
848                      const gl::Offset &dstOffset,
849                      const gl::Extents &copySize,
850                      const VkImageSubresourceLayers &srcSubresources,
851                      const VkImageSubresourceLayers &dstSubresources,
852                      CommandBuffer *commandBuffer);
853 
854     angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
855 
856     // Resolve this image into a destination image.  This image should be in the TransferSrc layout.
857     // The destination image is automatically transitioned into TransferDst.
858     void resolve(ImageHelper *dest, const VkImageResolve &region, CommandBuffer *commandBuffer);
859 
860     // Data staging
861     void removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index);
862 
863     angle::Result stageSubresourceUpdateImpl(ContextVk *contextVk,
864                                              const gl::ImageIndex &index,
865                                              const gl::Extents &glExtents,
866                                              const gl::Offset &offset,
867                                              const gl::InternalFormat &formatInfo,
868                                              const gl::PixelUnpackState &unpack,
869                                              GLenum type,
870                                              const uint8_t *pixels,
871                                              const Format &vkFormat,
872                                              const GLuint inputRowPitch,
873                                              const GLuint inputDepthPitch,
874                                              const GLuint inputSkipBytes);
875 
876     angle::Result stageSubresourceUpdate(ContextVk *contextVk,
877                                          const gl::ImageIndex &index,
878                                          const gl::Extents &glExtents,
879                                          const gl::Offset &offset,
880                                          const gl::InternalFormat &formatInfo,
881                                          const gl::PixelUnpackState &unpack,
882                                          GLenum type,
883                                          const uint8_t *pixels,
884                                          const Format &vkFormat);
885 
886     angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk,
887                                                    size_t allocationSize,
888                                                    const gl::ImageIndex &imageIndex,
889                                                    const gl::Extents &glExtents,
890                                                    const gl::Offset &offset,
891                                                    uint8_t **destData);
892 
893     angle::Result stageSubresourceUpdateFromBuffer(ContextVk *contextVk,
894                                                    size_t allocationSize,
895                                                    uint32_t mipLevel,
896                                                    uint32_t baseArrayLayer,
897                                                    uint32_t layerCount,
898                                                    const VkExtent3D &extent,
899                                                    const VkOffset3D &offset,
900                                                    BufferHelper *stagingBuffer,
901                                                    StagingBufferOffsetArray stagingOffsets);
902 
903     angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context,
904                                                         const gl::ImageIndex &index,
905                                                         const gl::Rectangle &sourceArea,
906                                                         const gl::Offset &dstOffset,
907                                                         const gl::Extents &dstExtent,
908                                                         const gl::InternalFormat &formatInfo,
909                                                         FramebufferVk *framebufferVk);
910 
911     void stageSubresourceUpdateFromImage(ImageHelper *image,
912                                          const gl::ImageIndex &index,
913                                          const gl::Offset &destOffset,
914                                          const gl::Extents &glExtents,
915                                          const VkImageType imageType);
916 
917     // Stage a clear based on robust resource init.
918     void stageRobustResourceClear(const gl::ImageIndex &index, const vk::Format &format);
919     void stageSubresourceClear(const gl::ImageIndex &index);
920 
921     // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
922     // dst.
923     angle::Result allocateStagingMemory(ContextVk *contextVk,
924                                         size_t sizeInBytes,
925                                         uint8_t **ptrOut,
926                                         BufferHelper **bufferOut,
927                                         StagingBufferOffsetArray *offsetOut,
928                                         bool *newBufferAllocatedOut);
929 
930     // Flushes staged updates to a range of levels and layers from start to (but not including) end.
931     // Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited
932     // layers may also be updated.
933     angle::Result flushStagedUpdates(ContextVk *contextVk,
934                                      uint32_t levelStart,
935                                      uint32_t levelEnd,
936                                      uint32_t layerStart,
937                                      uint32_t layerEnd,
938                                      CommandBuffer *commandBuffer);
939     // Creates a command buffer and flushes all staged updates.  This is used for one-time
940     // initialization of resources that we don't expect to accumulate further staged updates, such
941     // as with renderbuffers or surface images.
942     angle::Result flushAllStagedUpdates(ContextVk *contextVk);
943 
944     bool isUpdateStaged(uint32_t level, uint32_t layer);
hasStagedUpdates()945     bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); }
946 
947     // changeLayout automatically skips the layout change if it's unnecessary.  This function can be
948     // used to prevent creating a command graph node and subsequently a command buffer for the sole
949     // purpose of performing a transition (which may then not be issued).
950     bool isLayoutChangeNecessary(ImageLayout newLayout) const;
951 
952     template <typename CommandBufferT>
changeLayout(VkImageAspectFlags aspectMask,ImageLayout newLayout,CommandBufferT * commandBuffer)953     void changeLayout(VkImageAspectFlags aspectMask,
954                       ImageLayout newLayout,
955                       CommandBufferT *commandBuffer)
956     {
957         if (!isLayoutChangeNecessary(newLayout))
958         {
959             return;
960         }
961 
962         forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
963     }
964 
isQueueChangeNeccesary(uint32_t newQueueFamilyIndex)965     bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
966     {
967         return mCurrentQueueFamilyIndex != newQueueFamilyIndex;
968     }
969 
970     void changeLayoutAndQueue(VkImageAspectFlags aspectMask,
971                               ImageLayout newLayout,
972                               uint32_t newQueueFamilyIndex,
973                               CommandBuffer *commandBuffer);
974 
975     // If the image is used externally to GL, its layout could be different from ANGLE's internal
976     // state.  This function is used to inform ImageHelper of an external layout change.
977     void onExternalLayoutChange(ImageLayout newLayout);
978 
979     uint32_t getBaseLevel();
980     void setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel);
981 
982     angle::Result copyImageDataToBuffer(ContextVk *contextVk,
983                                         size_t sourceLevel,
984                                         uint32_t layerCount,
985                                         uint32_t baseLayer,
986                                         const gl::Box &sourceArea,
987                                         BufferHelper **bufferOut,
988                                         size_t *bufferSize,
989                                         StagingBufferOffsetArray *bufferOffsetsOut,
990                                         uint8_t **outDataPtr);
991 
992     static angle::Result GetReadPixelsParams(ContextVk *contextVk,
993                                              const gl::PixelPackState &packState,
994                                              gl::Buffer *packBuffer,
995                                              GLenum format,
996                                              GLenum type,
997                                              const gl::Rectangle &area,
998                                              const gl::Rectangle &clippedArea,
999                                              PackPixelsParams *paramsOut,
1000                                              GLuint *skipBytesOut);
1001 
1002     angle::Result readPixelsForGetImage(ContextVk *contextVk,
1003                                         const gl::PixelPackState &packState,
1004                                         gl::Buffer *packBuffer,
1005                                         uint32_t level,
1006                                         uint32_t layer,
1007                                         GLenum format,
1008                                         GLenum type,
1009                                         void *pixels);
1010 
1011     angle::Result readPixels(ContextVk *contextVk,
1012                              const gl::Rectangle &area,
1013                              const PackPixelsParams &packPixelsParams,
1014                              VkImageAspectFlagBits copyAspectFlags,
1015                              uint32_t level,
1016                              uint32_t layer,
1017                              void *pixels,
1018                              DynamicBuffer *stagingBuffer);
1019 
1020     angle::Result CalculateBufferInfo(ContextVk *contextVk,
1021                                       const gl::Extents &glExtents,
1022                                       const gl::InternalFormat &formatInfo,
1023                                       const gl::PixelUnpackState &unpack,
1024                                       GLenum type,
1025                                       bool is3D,
1026                                       GLuint *inputRowPitch,
1027                                       GLuint *inputDepthPitch,
1028                                       GLuint *inputSkipBytes);
1029 
1030   private:
1031     enum class UpdateSource
1032     {
1033         Clear,
1034         Buffer,
1035         Image,
1036     };
1037     struct ClearUpdate
1038     {
1039         VkImageAspectFlags aspectFlags;
1040         VkClearValue value;
1041         uint32_t levelIndex;
1042         uint32_t layerIndex;
1043         uint32_t layerCount;
1044     };
1045     struct BufferUpdate
1046     {
1047         BufferHelper *bufferHelper;
1048         VkBufferImageCopy copyRegion;
1049     };
1050     struct ImageUpdate
1051     {
1052         ImageHelper *image;
1053         VkImageCopy copyRegion;
1054     };
1055 
1056     struct SubresourceUpdate
1057     {
1058         SubresourceUpdate();
1059         SubresourceUpdate(BufferHelper *bufferHelperIn, const VkBufferImageCopy &copyRegion);
1060         SubresourceUpdate(ImageHelper *image, const VkImageCopy &copyRegion);
1061         SubresourceUpdate(VkImageAspectFlags aspectFlags,
1062                           const VkClearValue &clearValue,
1063                           const gl::ImageIndex &imageIndex);
1064         SubresourceUpdate(const SubresourceUpdate &other);
1065 
1066         void release(RendererVk *renderer);
1067 
dstSubresourceSubresourceUpdate1068         const VkImageSubresourceLayers &dstSubresource() const
1069         {
1070             ASSERT(updateSource == UpdateSource::Buffer || updateSource == UpdateSource::Image);
1071             return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource
1072                                                         : image.copyRegion.dstSubresource;
1073         }
1074         bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const;
1075 
1076         UpdateSource updateSource;
1077         union
1078         {
1079             ClearUpdate clear;
1080             BufferUpdate buffer;
1081             ImageUpdate image;
1082         };
1083     };
1084 
1085     // Generalized to accept both "primary" and "secondary" command buffers.
1086     template <typename CommandBufferT>
1087     void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
1088                                    ImageLayout newLayout,
1089                                    uint32_t newQueueFamilyIndex,
1090                                    CommandBufferT *commandBuffer);
1091 
1092     // If the image has emulated channels, we clear them once so as not to leave garbage on those
1093     // channels.
1094     void stageClearIfEmulatedFormat(Context *context);
1095 
1096     void clearColor(const VkClearColorValue &color,
1097                     uint32_t baseMipLevel,
1098                     uint32_t levelCount,
1099                     uint32_t baseArrayLayer,
1100                     uint32_t layerCount,
1101                     CommandBuffer *commandBuffer);
1102 
1103     void clearDepthStencil(VkImageAspectFlags clearAspectFlags,
1104                            const VkClearDepthStencilValue &depthStencil,
1105                            uint32_t baseMipLevel,
1106                            uint32_t levelCount,
1107                            uint32_t baseArrayLayer,
1108                            uint32_t layerCount,
1109                            CommandBuffer *commandBuffer);
1110 
1111     angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size);
1112 
1113     void appendSubresourceUpdate(SubresourceUpdate &&update);
1114     void prependSubresourceUpdate(SubresourceUpdate &&update);
1115     void resetCachedProperties();
1116 
1117     // Vulkan objects.
1118     Image mImage;
1119     DeviceMemory mDeviceMemory;
1120 
1121     // Image properties.
1122     VkImageType mImageType;
1123     VkExtent3D mExtents;
1124     const Format *mFormat;
1125     GLint mSamples;
1126     Serial mSerial;
1127 
1128     // Current state.
1129     ImageLayout mCurrentLayout;
1130     uint32_t mCurrentQueueFamilyIndex;
1131 
1132     // Cached properties.
1133     uint32_t mBaseLevel;
1134     uint32_t mMaxLevel;
1135     uint32_t mLayerCount;
1136     uint32_t mLevelCount;
1137 
1138     // Staging buffer
1139     DynamicBuffer mStagingBuffer;
1140     std::vector<SubresourceUpdate> mSubresourceUpdates;
1141 };
1142 
1143 // A vector of image views, such as one per level or one per layer.
1144 using ImageViewVector = std::vector<ImageView>;
1145 
1146 // A vector of vector of image views.  Primary index is layer, secondary index is level.
1147 using LayerLevelImageViewVector = std::vector<ImageViewVector>;
1148 
1149 class ImageViewHelper : angle::NonCopyable
1150 {
1151   public:
1152     ImageViewHelper();
1153     ImageViewHelper(ImageViewHelper &&other);
1154     ~ImageViewHelper();
1155 
1156     void release(RendererVk *renderer);
1157     void destroy(VkDevice device);
1158 
getReadImageView()1159     const ImageView &getReadImageView() const { return mReadImageView; }
getFetchImageView()1160     const ImageView &getFetchImageView() const { return mFetchImageView; }
getStencilReadImageView()1161     const ImageView &getStencilReadImageView() const { return mStencilReadImageView; }
1162 
1163     // Used when initialized RenderTargets.
hasStencilReadImageView()1164     bool hasStencilReadImageView() const { return mStencilReadImageView.valid(); }
1165 
hasFetchImageView()1166     bool hasFetchImageView() const { return mFetchImageView.valid(); }
1167 
1168     // Store reference to usage in graph.
retain(ResourceUseList * resourceUseList)1169     void retain(ResourceUseList *resourceUseList) const { resourceUseList->add(mUse); }
1170 
1171     // Creates views with multiple layers and levels.
1172     angle::Result initReadViews(ContextVk *contextVk,
1173                                 gl::TextureType viewType,
1174                                 const ImageHelper &image,
1175                                 const Format &format,
1176                                 const gl::SwizzleState &swizzleState,
1177                                 uint32_t baseLevel,
1178                                 uint32_t levelCount,
1179                                 uint32_t baseLayer,
1180                                 uint32_t layerCount);
1181 
1182     // Creates a view with all layers of the level.
1183     angle::Result getLevelDrawImageView(ContextVk *contextVk,
1184                                         gl::TextureType viewType,
1185                                         const ImageHelper &image,
1186                                         uint32_t level,
1187                                         uint32_t layer,
1188                                         const ImageView **imageViewOut);
1189 
1190     // Creates a view with a single layer of the level.
1191     angle::Result getLevelLayerDrawImageView(ContextVk *contextVk,
1192                                              const ImageHelper &image,
1193                                              uint32_t level,
1194                                              uint32_t layer,
1195                                              const ImageView **imageViewOut);
1196 
1197   private:
1198     // Lifetime.
1199     SharedResourceUse mUse;
1200 
1201     // Read views.
1202     ImageView mReadImageView;
1203     ImageView mFetchImageView;
1204     ImageView mStencilReadImageView;
1205 
1206     // Draw views.
1207     ImageViewVector mLevelDrawImageViews;
1208     LayerLevelImageViewVector mLayerLevelDrawImageViews;
1209 };
1210 
1211 // The SamplerHelper allows a Sampler to be coupled with a resource lifetime.
1212 class SamplerHelper final : angle::NonCopyable
1213 {
1214   public:
1215     SamplerHelper();
1216     ~SamplerHelper();
1217 
1218     void release(RendererVk *renderer);
1219 
valid()1220     bool valid() const { return mSampler.valid(); }
get()1221     Sampler &get() { return mSampler; }
get()1222     const Sampler &get() const { return mSampler; }
1223 
retain(ResourceUseList * resourceUseList)1224     void retain(ResourceUseList *resourceUseList) { resourceUseList->add(mUse); }
1225 
1226   private:
1227     SharedResourceUse mUse;
1228     Sampler mSampler;
1229 };
1230 
1231 class FramebufferHelper : public Resource
1232 {
1233   public:
1234     FramebufferHelper();
1235     ~FramebufferHelper() override;
1236 
1237     FramebufferHelper(FramebufferHelper &&other);
1238     FramebufferHelper &operator=(FramebufferHelper &&other);
1239 
1240     angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo);
1241     void release(ContextVk *contextVk);
1242 
valid()1243     bool valid() { return mFramebuffer.valid(); }
1244 
getFramebuffer()1245     const Framebuffer &getFramebuffer() const
1246     {
1247         ASSERT(mFramebuffer.valid());
1248         return mFramebuffer;
1249     }
1250 
getFramebuffer()1251     Framebuffer &getFramebuffer()
1252     {
1253         ASSERT(mFramebuffer.valid());
1254         return mFramebuffer;
1255     }
1256 
1257   private:
1258     // Vulkan object.
1259     Framebuffer mFramebuffer;
1260 };
1261 
1262 // A special command graph resource to hold resource dependencies for dispatch calls.  It's the
1263 // equivalent of FramebufferHelper, though it doesn't contain a Vulkan object.
1264 class DispatchHelper : public Resource
1265 {
1266   public:
1267     DispatchHelper();
1268     ~DispatchHelper() override;
1269 };
1270 
1271 class ShaderProgramHelper : angle::NonCopyable
1272 {
1273   public:
1274     ShaderProgramHelper();
1275     ~ShaderProgramHelper();
1276 
1277     bool valid(const gl::ShaderType shaderType) const;
1278     void destroy(VkDevice device);
1279     void release(ContextVk *contextVk);
1280 
isGraphicsProgram()1281     bool isGraphicsProgram() const
1282     {
1283         ASSERT((mShaders[gl::ShaderType::Vertex].valid() ||
1284                 mShaders[gl::ShaderType::Fragment].valid()) !=
1285                mShaders[gl::ShaderType::Compute].valid());
1286         return !mShaders[gl::ShaderType::Compute].valid();
1287     }
1288 
getShader(gl::ShaderType shaderType)1289     ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); }
1290 
1291     void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader);
1292     void enableSpecializationConstant(sh::vk::SpecializationConstantId id);
1293 
1294     // For getting a Pipeline and from the pipeline cache.
getGraphicsPipeline(ContextVk * contextVk,RenderPassCache * renderPassCache,const PipelineCache & pipelineCache,Serial currentQueueSerial,const PipelineLayout & pipelineLayout,const GraphicsPipelineDesc & pipelineDesc,const gl::AttributesMask & activeAttribLocationsMask,const gl::ComponentTypeMask & programAttribsTypeMask,const GraphicsPipelineDesc ** descPtrOut,PipelineHelper ** pipelineOut)1295     ANGLE_INLINE angle::Result getGraphicsPipeline(
1296         ContextVk *contextVk,
1297         RenderPassCache *renderPassCache,
1298         const PipelineCache &pipelineCache,
1299         Serial currentQueueSerial,
1300         const PipelineLayout &pipelineLayout,
1301         const GraphicsPipelineDesc &pipelineDesc,
1302         const gl::AttributesMask &activeAttribLocationsMask,
1303         const gl::ComponentTypeMask &programAttribsTypeMask,
1304         const GraphicsPipelineDesc **descPtrOut,
1305         PipelineHelper **pipelineOut)
1306     {
1307         // Pull in a compatible RenderPass.
1308         RenderPass *compatibleRenderPass = nullptr;
1309         ANGLE_TRY(renderPassCache->getCompatibleRenderPass(contextVk, currentQueueSerial,
1310                                                            pipelineDesc.getRenderPassDesc(),
1311                                                            &compatibleRenderPass));
1312 
1313         ShaderModule *vertexShader   = &mShaders[gl::ShaderType::Vertex].get().get();
1314         ShaderModule *fragmentShader = mShaders[gl::ShaderType::Fragment].valid()
1315                                            ? &mShaders[gl::ShaderType::Fragment].get().get()
1316                                            : nullptr;
1317         ShaderModule *geometryShader = mShaders[gl::ShaderType::Geometry].valid()
1318                                            ? &mShaders[gl::ShaderType::Geometry].get().get()
1319                                            : nullptr;
1320 
1321         return mGraphicsPipelines.getPipeline(
1322             contextVk, pipelineCache, *compatibleRenderPass, pipelineLayout,
1323             activeAttribLocationsMask, programAttribsTypeMask, vertexShader, fragmentShader,
1324             geometryShader, mSpecializationConstants, pipelineDesc, descPtrOut, pipelineOut);
1325     }
1326 
1327     angle::Result getComputePipeline(Context *context,
1328                                      const PipelineLayout &pipelineLayout,
1329                                      PipelineAndSerial **pipelineOut);
1330 
1331   private:
1332     gl::ShaderMap<BindingPointer<ShaderAndSerial>> mShaders;
1333     GraphicsPipelineCache mGraphicsPipelines;
1334 
1335     // We should probably use PipelineHelper here so we can remove PipelineAndSerial.
1336     PipelineAndSerial mComputePipeline;
1337 
1338     // Specialization constants, currently only used by the graphics queue.
1339     vk::SpecializationConstantBitSet mSpecializationConstants;
1340 };
1341 }  // namespace vk
1342 }  // namespace rx
1343 
1344 #endif  // LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_
1345