xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/vk_utils.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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_utils:
7 //    Helper functions for the Vulkan Renderer.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
11 #define LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
12 
13 #include <atomic>
14 #include <limits>
15 #include <queue>
16 
17 #include "GLSLANG/ShaderLang.h"
18 #include "common/FixedVector.h"
19 #include "common/Optional.h"
20 #include "common/PackedEnums.h"
21 #include "common/SimpleMutex.h"
22 #include "common/WorkerThread.h"
23 #include "common/backtrace_utils.h"
24 #include "common/debug.h"
25 #include "libANGLE/Error.h"
26 #include "libANGLE/Observer.h"
27 #include "libANGLE/angletypes.h"
28 #include "libANGLE/renderer/serial_utils.h"
29 #include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
30 #include "libANGLE/renderer/vulkan/SecondaryCommandPool.h"
31 #include "libANGLE/renderer/vulkan/VulkanSecondaryCommandBuffer.h"
32 #include "libANGLE/renderer/vulkan/vk_wrapper.h"
33 #include "platform/autogen/FeaturesVk_autogen.h"
34 #include "vulkan/vulkan_fuchsia_ext.h"
35 
36 #define ANGLE_GL_OBJECTS_X(PROC) \
37     PROC(Buffer)                 \
38     PROC(Context)                \
39     PROC(Framebuffer)            \
40     PROC(MemoryObject)           \
41     PROC(Overlay)                \
42     PROC(Program)                \
43     PROC(ProgramExecutable)      \
44     PROC(ProgramPipeline)        \
45     PROC(Query)                  \
46     PROC(Renderbuffer)           \
47     PROC(Sampler)                \
48     PROC(Semaphore)              \
49     PROC(Texture)                \
50     PROC(TransformFeedback)      \
51     PROC(VertexArray)
52 
53 #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
54 
55 namespace egl
56 {
57 class Display;
58 class Image;
59 class ShareGroup;
60 }  // namespace egl
61 
62 namespace gl
63 {
64 class MockOverlay;
65 class ProgramExecutable;
66 struct RasterizerState;
67 struct SwizzleState;
68 struct VertexAttribute;
69 class VertexBinding;
70 
71 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT)
72 }  // namespace gl
73 
74 #define ANGLE_PRE_DECLARE_VK_OBJECT(OBJ) class OBJ##Vk;
75 
76 namespace rx
77 {
78 class DisplayVk;
79 class ImageVk;
80 class ProgramExecutableVk;
81 class RenderbufferVk;
82 class RenderTargetVk;
83 class RenderPassCache;
84 class ShareGroupVk;
85 }  // namespace rx
86 
87 namespace angle
88 {
89 egl::Error ToEGL(Result result, EGLint errorCode);
90 }  // namespace angle
91 
92 namespace rx
93 {
94 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_VK_OBJECT)
95 
96 const char *VulkanResultString(VkResult result);
97 
98 constexpr size_t kMaxVulkanLayers = 20;
99 using VulkanLayerVector           = angle::FixedVector<const char *, kMaxVulkanLayers>;
100 
101 // Verify that validation layers are available.
102 bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerProps,
103                                   bool mustHaveLayers,
104                                   VulkanLayerVector *enabledLayerNames);
105 
106 enum class TextureDimension
107 {
108     TEX_2D,
109     TEX_CUBE,
110     TEX_3D,
111     TEX_2D_ARRAY,
112 };
113 
114 enum class BufferUsageType
115 {
116     Static      = 0,
117     Dynamic     = 1,
118     InvalidEnum = 2,
119     EnumCount   = InvalidEnum,
120 };
121 
122 // A maximum offset of 4096 covers almost every Vulkan driver on desktop (80%) and mobile (99%). The
123 // next highest values to meet native drivers are 16 bits or 32 bits.
124 constexpr uint32_t kAttributeOffsetMaxBits = 15;
125 constexpr uint32_t kInvalidMemoryTypeIndex = UINT32_MAX;
126 constexpr uint32_t kInvalidMemoryHeapIndex = UINT32_MAX;
127 
128 namespace vk
129 {
130 class Renderer;
131 
132 // Used for memory allocation tracking.
133 enum class MemoryAllocationType;
134 
135 enum class MemoryHostVisibility
136 {
137     NonVisible,
138     Visible
139 };
140 
141 // Encapsulate the graphics family index and VkQueue index (as seen in vkGetDeviceQueue API
142 // arguments) into one integer so that we can easily pass around without introduce extra overhead..
143 class DeviceQueueIndex final
144 {
145   public:
DeviceQueueIndex()146     constexpr DeviceQueueIndex()
147         : mFamilyIndex(kInvalidQueueFamilyIndex), mQueueIndex(kInvalidQueueIndex)
148     {}
DeviceQueueIndex(uint32_t familyIndex)149     constexpr DeviceQueueIndex(uint32_t familyIndex)
150         : mFamilyIndex((int8_t)familyIndex), mQueueIndex(kInvalidQueueIndex)
151     {
152         ASSERT(static_cast<uint32_t>(mFamilyIndex) == familyIndex);
153     }
DeviceQueueIndex(uint32_t familyIndex,uint32_t queueIndex)154     DeviceQueueIndex(uint32_t familyIndex, uint32_t queueIndex)
155         : mFamilyIndex((int8_t)familyIndex), mQueueIndex((int8_t)queueIndex)
156     {
157         // Ensure the value we actually don't truncate the useful bits.
158         ASSERT(static_cast<uint32_t>(mFamilyIndex) == familyIndex);
159         ASSERT(static_cast<uint32_t>(mQueueIndex) == queueIndex);
160     }
DeviceQueueIndex(const DeviceQueueIndex & other)161     DeviceQueueIndex(const DeviceQueueIndex &other) { *this = other; }
162 
163     DeviceQueueIndex &operator=(const DeviceQueueIndex &other)
164     {
165         mValue = other.mValue;
166         return *this;
167     }
168 
familyIndex()169     constexpr uint32_t familyIndex() const { return mFamilyIndex; }
queueIndex()170     constexpr uint32_t queueIndex() const { return mQueueIndex; }
171 
172     bool operator==(const DeviceQueueIndex &other) const { return mValue == other.mValue; }
173     bool operator!=(const DeviceQueueIndex &other) const { return mValue != other.mValue; }
174 
175   private:
176     static constexpr int8_t kInvalidQueueFamilyIndex = -1;
177     static constexpr int8_t kInvalidQueueIndex       = -1;
178     // The expectation is that these indices are small numbers that could easily fit into int8_t.
179     // int8_t is used instead of uint8_t because we need to handle VK_QUEUE_FAMILY_FOREIGN_EXT and
180     // VK_QUEUE_FAMILY_EXTERNAL properly which are essentially are negative values.
181     union
182     {
183         struct
184         {
185             int8_t mFamilyIndex;
186             int8_t mQueueIndex;
187         };
188         uint16_t mValue;
189     };
190 };
191 static constexpr DeviceQueueIndex kInvalidDeviceQueueIndex = DeviceQueueIndex();
192 static constexpr DeviceQueueIndex kForeignDeviceQueueIndex =
193     DeviceQueueIndex(VK_QUEUE_FAMILY_FOREIGN_EXT);
194 static constexpr DeviceQueueIndex kExternalDeviceQueueIndex =
195     DeviceQueueIndex(VK_QUEUE_FAMILY_EXTERNAL);
196 static_assert(kForeignDeviceQueueIndex.familyIndex() == VK_QUEUE_FAMILY_FOREIGN_EXT);
197 static_assert(kExternalDeviceQueueIndex.familyIndex() == VK_QUEUE_FAMILY_EXTERNAL);
198 static_assert(kInvalidDeviceQueueIndex.familyIndex() == VK_QUEUE_FAMILY_IGNORED);
199 
200 // A packed attachment index interface with vulkan API
201 class PackedAttachmentIndex final
202 {
203   public:
PackedAttachmentIndex(uint32_t index)204     explicit constexpr PackedAttachmentIndex(uint32_t index) : mAttachmentIndex(index) {}
205     constexpr PackedAttachmentIndex(const PackedAttachmentIndex &other)            = default;
206     constexpr PackedAttachmentIndex &operator=(const PackedAttachmentIndex &other) = default;
207 
get()208     constexpr uint32_t get() const { return mAttachmentIndex; }
209     PackedAttachmentIndex &operator++()
210     {
211         ++mAttachmentIndex;
212         return *this;
213     }
214     constexpr bool operator==(const PackedAttachmentIndex &other) const
215     {
216         return mAttachmentIndex == other.mAttachmentIndex;
217     }
218     constexpr bool operator!=(const PackedAttachmentIndex &other) const
219     {
220         return mAttachmentIndex != other.mAttachmentIndex;
221     }
222     constexpr bool operator<(const PackedAttachmentIndex &other) const
223     {
224         return mAttachmentIndex < other.mAttachmentIndex;
225     }
226 
227   private:
228     uint32_t mAttachmentIndex;
229 };
230 using PackedAttachmentCount                                    = PackedAttachmentIndex;
231 static constexpr PackedAttachmentIndex kAttachmentIndexInvalid = PackedAttachmentIndex(-1);
232 static constexpr PackedAttachmentIndex kAttachmentIndexZero    = PackedAttachmentIndex(0);
233 
234 // Prepend ptr to the pNext chain at chainStart
235 template <typename VulkanStruct1, typename VulkanStruct2>
AddToPNextChain(VulkanStruct1 * chainStart,VulkanStruct2 * ptr)236 void AddToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
237 {
238     // Catch bugs where this function is called with `&pointer` instead of `pointer`.
239     static_assert(!std::is_pointer<VulkanStruct1>::value);
240     static_assert(!std::is_pointer<VulkanStruct2>::value);
241 
242     ASSERT(ptr->pNext == nullptr);
243 
244     VkBaseOutStructure *localPtr = reinterpret_cast<VkBaseOutStructure *>(chainStart);
245     ptr->pNext                   = localPtr->pNext;
246     localPtr->pNext              = reinterpret_cast<VkBaseOutStructure *>(ptr);
247 }
248 
249 // Append ptr to the end of the chain
250 template <typename VulkanStruct1, typename VulkanStruct2>
AppendToPNextChain(VulkanStruct1 * chainStart,VulkanStruct2 * ptr)251 void AppendToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
252 {
253     static_assert(!std::is_pointer<VulkanStruct1>::value);
254     static_assert(!std::is_pointer<VulkanStruct2>::value);
255 
256     if (!ptr)
257     {
258         return;
259     }
260 
261     VkBaseOutStructure *endPtr = reinterpret_cast<VkBaseOutStructure *>(chainStart);
262     while (endPtr->pNext)
263     {
264         endPtr = endPtr->pNext;
265     }
266     endPtr->pNext = reinterpret_cast<VkBaseOutStructure *>(ptr);
267 }
268 
269 class QueueSerialIndexAllocator final
270 {
271   public:
QueueSerialIndexAllocator()272     QueueSerialIndexAllocator() : mLargestIndexEverAllocated(kInvalidQueueSerialIndex)
273     {
274         // Start with every index is free
275         mFreeIndexBitSetArray.set();
276         ASSERT(mFreeIndexBitSetArray.all());
277     }
allocate()278     SerialIndex allocate()
279     {
280         std::lock_guard<angle::SimpleMutex> lock(mMutex);
281         if (mFreeIndexBitSetArray.none())
282         {
283             ERR() << "Run out of queue serial index. All " << kMaxQueueSerialIndexCount
284                   << " indices are used.";
285             return kInvalidQueueSerialIndex;
286         }
287         SerialIndex index = static_cast<SerialIndex>(mFreeIndexBitSetArray.first());
288         ASSERT(index < kMaxQueueSerialIndexCount);
289         mFreeIndexBitSetArray.reset(index);
290         mLargestIndexEverAllocated = (~mFreeIndexBitSetArray).last();
291         return index;
292     }
293 
release(SerialIndex index)294     void release(SerialIndex index)
295     {
296         std::lock_guard<angle::SimpleMutex> lock(mMutex);
297         ASSERT(index <= mLargestIndexEverAllocated);
298         ASSERT(!mFreeIndexBitSetArray.test(index));
299         mFreeIndexBitSetArray.set(index);
300         // mLargestIndexEverAllocated is for optimization. Even if we released queueIndex, we may
301         // still have resources still have serial the index. Thus do not decrement
302         // mLargestIndexEverAllocated here. The only downside is that we may get into slightly less
303         // optimal code path in GetBatchCountUpToSerials.
304     }
305 
getLargestIndexEverAllocated()306     size_t getLargestIndexEverAllocated() const
307     {
308         return mLargestIndexEverAllocated.load(std::memory_order_consume);
309     }
310 
311   private:
312     angle::BitSetArray<kMaxQueueSerialIndexCount> mFreeIndexBitSetArray;
313     std::atomic<size_t> mLargestIndexEverAllocated;
314     angle::SimpleMutex mMutex;
315 };
316 
317 class [[nodiscard]] ScopedQueueSerialIndex final : angle::NonCopyable
318 {
319   public:
ScopedQueueSerialIndex()320     ScopedQueueSerialIndex() : mIndex(kInvalidQueueSerialIndex), mIndexAllocator(nullptr) {}
~ScopedQueueSerialIndex()321     ~ScopedQueueSerialIndex()
322     {
323         if (mIndex != kInvalidQueueSerialIndex)
324         {
325             ASSERT(mIndexAllocator != nullptr);
326             mIndexAllocator->release(mIndex);
327         }
328     }
329 
init(SerialIndex index,QueueSerialIndexAllocator * indexAllocator)330     void init(SerialIndex index, QueueSerialIndexAllocator *indexAllocator)
331     {
332         ASSERT(mIndex == kInvalidQueueSerialIndex);
333         ASSERT(index != kInvalidQueueSerialIndex);
334         ASSERT(indexAllocator != nullptr);
335         mIndex          = index;
336         mIndexAllocator = indexAllocator;
337     }
338 
get()339     SerialIndex get() const { return mIndex; }
340 
341   private:
342     SerialIndex mIndex;
343     QueueSerialIndexAllocator *mIndexAllocator;
344 };
345 
346 class RefCountedEventsGarbageRecycler;
347 // Abstracts error handling. Implemented by ContextVk for GL, DisplayVk for EGL, worker threads,
348 // CLContextVk etc.
349 class Context : angle::NonCopyable
350 {
351   public:
352     Context(Renderer *renderer);
353     virtual ~Context();
354 
355     virtual void handleError(VkResult result,
356                              const char *file,
357                              const char *function,
358                              unsigned int line) = 0;
359     VkDevice getDevice() const;
getRenderer()360     Renderer *getRenderer() const { return mRenderer; }
361     const angle::FeaturesVk &getFeatures() const;
362 
getPerfCounters()363     const angle::VulkanPerfCounters &getPerfCounters() const { return mPerfCounters; }
getPerfCounters()364     angle::VulkanPerfCounters &getPerfCounters() { return mPerfCounters; }
getRefCountedEventsGarbageRecycler()365     RefCountedEventsGarbageRecycler *getRefCountedEventsGarbageRecycler()
366     {
367         return mShareGroupRefCountedEventsGarbageRecycler;
368     }
getDeviceQueueIndex()369     const DeviceQueueIndex &getDeviceQueueIndex() const { return mDeviceQueueIndex; }
370 
371   protected:
372     Renderer *const mRenderer;
373     // Stash the ShareGroupVk's RefCountedEventRecycler here ImageHelper to conveniently access
374     RefCountedEventsGarbageRecycler *mShareGroupRefCountedEventsGarbageRecycler;
375     DeviceQueueIndex mDeviceQueueIndex;
376     angle::VulkanPerfCounters mPerfCounters;
377 };
378 
379 // Abstract global operations that are handled differently between EGL and OpenCL.
380 class GlobalOps : angle::NonCopyable
381 {
382   public:
383     virtual ~GlobalOps() = default;
384 
385     virtual void putBlob(const angle::BlobCacheKey &key, const angle::MemoryBuffer &value) = 0;
386     virtual bool getBlob(const angle::BlobCacheKey &key, angle::BlobCacheValue *valueOut)  = 0;
387 
388     virtual std::shared_ptr<angle::WaitableEvent> postMultiThreadWorkerTask(
389         const std::shared_ptr<angle::Closure> &task) = 0;
390 
391     virtual void notifyDeviceLost() = 0;
392 };
393 
394 class RenderPassDesc;
395 
396 #if ANGLE_USE_CUSTOM_VULKAN_OUTSIDE_RENDER_PASS_CMD_BUFFERS
397 using OutsideRenderPassCommandBuffer = priv::SecondaryCommandBuffer;
398 #else
399 using OutsideRenderPassCommandBuffer = VulkanSecondaryCommandBuffer;
400 #endif
401 #if ANGLE_USE_CUSTOM_VULKAN_RENDER_PASS_CMD_BUFFERS
402 using RenderPassCommandBuffer = priv::SecondaryCommandBuffer;
403 #else
404 using RenderPassCommandBuffer = VulkanSecondaryCommandBuffer;
405 #endif
406 
407 struct SecondaryCommandPools
408 {
409     SecondaryCommandPool outsideRenderPassPool;
410     SecondaryCommandPool renderPassPool;
411 };
412 
413 VkImageAspectFlags GetDepthStencilAspectFlags(const angle::Format &format);
414 VkImageAspectFlags GetFormatAspectFlags(const angle::Format &format);
415 
416 template <typename T>
417 struct ImplTypeHelper;
418 
419 // clang-format off
420 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
421 template<>                             \
422 struct ImplTypeHelper<gl::OBJ>         \
423 {                                      \
424     using ImplType = OBJ##Vk;          \
425 };
426 // clang-format on
427 
428 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
429 
430 template <>
431 struct ImplTypeHelper<gl::MockOverlay>
432 {
433     using ImplType = OverlayVk;
434 };
435 
436 template <>
437 struct ImplTypeHelper<egl::Display>
438 {
439     using ImplType = DisplayVk;
440 };
441 
442 template <>
443 struct ImplTypeHelper<egl::Image>
444 {
445     using ImplType = ImageVk;
446 };
447 
448 template <>
449 struct ImplTypeHelper<egl::ShareGroup>
450 {
451     using ImplType = ShareGroupVk;
452 };
453 
454 template <typename T>
455 using GetImplType = typename ImplTypeHelper<T>::ImplType;
456 
457 template <typename T>
458 GetImplType<T> *GetImpl(const T *glObject)
459 {
460     return GetImplAs<GetImplType<T>>(glObject);
461 }
462 
463 template <typename T>
464 GetImplType<T> *SafeGetImpl(const T *glObject)
465 {
466     return SafeGetImplAs<GetImplType<T>>(glObject);
467 }
468 
469 template <>
470 inline OverlayVk *GetImpl(const gl::MockOverlay *glObject)
471 {
472     return nullptr;
473 }
474 
475 // Reference to a deleted object. The object is due to be destroyed at some point in the future.
476 // |mHandleType| determines the type of the object and which destroy function should be called.
477 class GarbageObject
478 {
479   public:
480     GarbageObject();
481     GarbageObject(GarbageObject &&other);
482     GarbageObject &operator=(GarbageObject &&rhs);
483 
484     bool valid() const { return mHandle != VK_NULL_HANDLE; }
485     void destroy(Renderer *renderer);
486 
487     template <typename DerivedT, typename HandleT>
488     static GarbageObject Get(WrappedObject<DerivedT, HandleT> *object)
489     {
490         // Using c-style cast here to avoid conditional compile for MSVC 32-bit
491         //  which fails to compile with reinterpret_cast, requiring static_cast.
492         return GarbageObject(HandleTypeHelper<DerivedT>::kHandleType,
493                              (GarbageHandle)(object->release()));
494     }
495 
496   private:
497     VK_DEFINE_NON_DISPATCHABLE_HANDLE(GarbageHandle)
498     GarbageObject(HandleType handleType, GarbageHandle handle);
499 
500     HandleType mHandleType;
501     GarbageHandle mHandle;
502 };
503 
504 template <typename T>
505 GarbageObject GetGarbage(T *obj)
506 {
507     return GarbageObject::Get(obj);
508 }
509 
510 // A list of garbage objects. Has no object lifetime information.
511 using GarbageObjects = std::vector<GarbageObject>;
512 
513 class MemoryProperties final : angle::NonCopyable
514 {
515   public:
516     MemoryProperties();
517 
518     void init(VkPhysicalDevice physicalDevice);
519     bool hasLazilyAllocatedMemory() const;
520     VkResult findCompatibleMemoryIndex(Context *context,
521                                        const VkMemoryRequirements &memoryRequirements,
522                                        VkMemoryPropertyFlags requestedMemoryPropertyFlags,
523                                        bool isExternalMemory,
524                                        VkMemoryPropertyFlags *memoryPropertyFlagsOut,
525                                        uint32_t *indexOut) const;
526     void destroy();
527 
528     uint32_t getHeapIndexForMemoryType(uint32_t memoryType) const
529     {
530         if (memoryType == kInvalidMemoryTypeIndex)
531         {
532             return kInvalidMemoryHeapIndex;
533         }
534 
535         ASSERT(memoryType < getMemoryTypeCount());
536         return mMemoryProperties.memoryTypes[memoryType].heapIndex;
537     }
538 
539     VkDeviceSize getHeapSizeForMemoryType(uint32_t memoryType) const
540     {
541         uint32_t heapIndex = mMemoryProperties.memoryTypes[memoryType].heapIndex;
542         return mMemoryProperties.memoryHeaps[heapIndex].size;
543     }
544 
545     const VkMemoryType &getMemoryType(uint32_t i) const { return mMemoryProperties.memoryTypes[i]; }
546 
547     uint32_t getMemoryHeapCount() const { return mMemoryProperties.memoryHeapCount; }
548     uint32_t getMemoryTypeCount() const { return mMemoryProperties.memoryTypeCount; }
549 
550   private:
551     VkPhysicalDeviceMemoryProperties mMemoryProperties;
552 };
553 
554 // Similar to StagingImage, for Buffers.
555 class StagingBuffer final : angle::NonCopyable
556 {
557   public:
558     StagingBuffer();
559     void release(ContextVk *contextVk);
560     void collectGarbage(Renderer *renderer, const QueueSerial &queueSerial);
561     void destroy(Renderer *renderer);
562 
563     angle::Result init(Context *context, VkDeviceSize size, StagingUsage usage);
564 
565     Buffer &getBuffer() { return mBuffer; }
566     const Buffer &getBuffer() const { return mBuffer; }
567     size_t getSize() const { return mSize; }
568 
569   private:
570     Buffer mBuffer;
571     Allocation mAllocation;
572     size_t mSize;
573 };
574 
575 angle::Result InitMappableAllocation(Context *context,
576                                      const Allocator &allocator,
577                                      Allocation *allocation,
578                                      VkDeviceSize size,
579                                      int value,
580                                      VkMemoryPropertyFlags memoryPropertyFlags);
581 
582 VkResult AllocateBufferMemory(Context *context,
583                               vk::MemoryAllocationType memoryAllocationType,
584                               VkMemoryPropertyFlags requestedMemoryPropertyFlags,
585                               VkMemoryPropertyFlags *memoryPropertyFlagsOut,
586                               const void *extraAllocationInfo,
587                               Buffer *buffer,
588                               uint32_t *memoryTypeIndexOut,
589                               DeviceMemory *deviceMemoryOut,
590                               VkDeviceSize *sizeOut);
591 
592 VkResult AllocateImageMemory(Context *context,
593                              vk::MemoryAllocationType memoryAllocationType,
594                              VkMemoryPropertyFlags memoryPropertyFlags,
595                              VkMemoryPropertyFlags *memoryPropertyFlagsOut,
596                              const void *extraAllocationInfo,
597                              Image *image,
598                              uint32_t *memoryTypeIndexOut,
599                              DeviceMemory *deviceMemoryOut,
600                              VkDeviceSize *sizeOut);
601 
602 VkResult AllocateImageMemoryWithRequirements(Context *context,
603                                              vk::MemoryAllocationType memoryAllocationType,
604                                              VkMemoryPropertyFlags memoryPropertyFlags,
605                                              const VkMemoryRequirements &memoryRequirements,
606                                              const void *extraAllocationInfo,
607                                              const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
608                                              Image *image,
609                                              uint32_t *memoryTypeIndexOut,
610                                              DeviceMemory *deviceMemoryOut);
611 
612 VkResult AllocateBufferMemoryWithRequirements(Context *context,
613                                               MemoryAllocationType memoryAllocationType,
614                                               VkMemoryPropertyFlags memoryPropertyFlags,
615                                               const VkMemoryRequirements &memoryRequirements,
616                                               const void *extraAllocationInfo,
617                                               Buffer *buffer,
618                                               VkMemoryPropertyFlags *memoryPropertyFlagsOut,
619                                               uint32_t *memoryTypeIndexOut,
620                                               DeviceMemory *deviceMemoryOut);
621 
622 gl::TextureType Get2DTextureType(uint32_t layerCount, GLint samples);
623 
624 enum class RecordingMode
625 {
626     Start,
627     Append,
628 };
629 
630 // Helper class to handle RAII patterns for initialization. Requires that T have a destroy method
631 // that takes a VkDevice and returns void.
632 template <typename T>
633 class [[nodiscard]] DeviceScoped final : angle::NonCopyable
634 {
635   public:
636     DeviceScoped(VkDevice device) : mDevice(device) {}
637     ~DeviceScoped() { mVar.destroy(mDevice); }
638 
639     const T &get() const { return mVar; }
640     T &get() { return mVar; }
641 
642     T &&release() { return std::move(mVar); }
643 
644   private:
645     VkDevice mDevice;
646     T mVar;
647 };
648 
649 template <typename T>
650 class [[nodiscard]] AllocatorScoped final : angle::NonCopyable
651 {
652   public:
653     AllocatorScoped(const Allocator &allocator) : mAllocator(allocator) {}
654     ~AllocatorScoped() { mVar.destroy(mAllocator); }
655 
656     const T &get() const { return mVar; }
657     T &get() { return mVar; }
658 
659     T &&release() { return std::move(mVar); }
660 
661   private:
662     const Allocator &mAllocator;
663     T mVar;
664 };
665 
666 // Similar to DeviceScoped, but releases objects instead of destroying them. Requires that T have a
667 // release method that takes a ContextVk * and returns void.
668 template <typename T>
669 class [[nodiscard]] ContextScoped final : angle::NonCopyable
670 {
671   public:
672     ContextScoped(ContextVk *contextVk) : mContextVk(contextVk) {}
673     ~ContextScoped() { mVar.release(mContextVk); }
674 
675     const T &get() const { return mVar; }
676     T &get() { return mVar; }
677 
678     T &&release() { return std::move(mVar); }
679 
680   private:
681     ContextVk *mContextVk;
682     T mVar;
683 };
684 
685 template <typename T>
686 class [[nodiscard]] RendererScoped final : angle::NonCopyable
687 {
688   public:
689     RendererScoped(Renderer *renderer) : mRenderer(renderer) {}
690     ~RendererScoped() { mVar.release(mRenderer); }
691 
692     const T &get() const { return mVar; }
693     T &get() { return mVar; }
694 
695     T &&release() { return std::move(mVar); }
696 
697   private:
698     Renderer *mRenderer;
699     T mVar;
700 };
701 
702 // This is a very simple RefCount class that has no autoreleasing.
703 template <typename T>
704 class RefCounted : angle::NonCopyable
705 {
706   public:
707     RefCounted() : mRefCount(0) {}
708     template <class... Args>
709     explicit RefCounted(Args &&...args) : mRefCount(0), mObject(std::forward<Args>(args)...)
710     {}
711     explicit RefCounted(T &&newObject) : mRefCount(0), mObject(std::move(newObject)) {}
712     ~RefCounted() { ASSERT(mRefCount == 0 && !mObject.valid()); }
713 
714     RefCounted(RefCounted &&copy) : mRefCount(copy.mRefCount), mObject(std::move(copy.mObject))
715     {
716         ASSERT(this != &copy);
717         copy.mRefCount = 0;
718     }
719 
720     RefCounted &operator=(RefCounted &&rhs)
721     {
722         std::swap(mRefCount, rhs.mRefCount);
723         mObject = std::move(rhs.mObject);
724         return *this;
725     }
726 
727     void addRef()
728     {
729         ASSERT(mRefCount != std::numeric_limits<uint32_t>::max());
730         mRefCount++;
731     }
732 
733     void releaseRef()
734     {
735         ASSERT(isReferenced());
736         mRefCount--;
737     }
738 
739     uint32_t getAndReleaseRef()
740     {
741         ASSERT(isReferenced());
742         return mRefCount--;
743     }
744 
745     bool isReferenced() const { return mRefCount != 0; }
746     uint32_t getRefCount() const { return mRefCount; }
747     bool isLastReferenceCount() const { return mRefCount == 1; }
748 
749     T &get() { return mObject; }
750     const T &get() const { return mObject; }
751 
752     // A debug function to validate that the reference count is as expected used for assertions.
753     bool isRefCountAsExpected(uint32_t expectedRefCount) { return mRefCount == expectedRefCount; }
754 
755   private:
756     uint32_t mRefCount;
757     T mObject;
758 };
759 
760 // Atomic version of RefCounted.  Used in the descriptor set and pipeline layout caches, which are
761 // accessed by link jobs.  No std::move is allowed due to the atomic ref count.
762 template <typename T>
763 class AtomicRefCounted : angle::NonCopyable
764 {
765   public:
766     AtomicRefCounted() : mRefCount(0) {}
767     explicit AtomicRefCounted(T &&newObject) : mRefCount(0), mObject(std::move(newObject)) {}
768     ~AtomicRefCounted() { ASSERT(mRefCount == 0 && !mObject.valid()); }
769 
770     void addRef()
771     {
772         ASSERT(mRefCount != std::numeric_limits<uint32_t>::max());
773         mRefCount.fetch_add(1, std::memory_order_relaxed);
774     }
775 
776     // Warning: method does not perform any synchronization, therefore can not be used along with
777     // following `!isReferenced()` call to check if object is not longer accessed by other threads.
778     // Use `getAndReleaseRef()` instead, when synchronization is required.
779     void releaseRef()
780     {
781         ASSERT(isReferenced());
782         mRefCount.fetch_sub(1, std::memory_order_relaxed);
783     }
784 
785     // Performs acquire-release memory synchronization. When result is "1", the object is
786     // guaranteed to be no longer in use by other threads, and may be safely destroyed or updated.
787     // Warning: do not mix this method and the unsynchronized `releaseRef()` call.
788     unsigned int getAndReleaseRef()
789     {
790         ASSERT(isReferenced());
791         return mRefCount.fetch_sub(1, std::memory_order_acq_rel);
792     }
793 
794     // Making decisions based on reference count is not thread safe, so it should not used in
795     // release build.
796 #if defined(ANGLE_ENABLE_ASSERTS)
797     // Warning: method does not perform any synchronization.  See `releaseRef()` for details.
798     // Method may be only used after external synchronization.
799     bool isReferenced() const { return mRefCount.load(std::memory_order_relaxed) != 0; }
800     uint32_t getRefCount() const { return mRefCount.load(std::memory_order_relaxed); }
801     // This is used by SharedPtr::unique, so needs strong ordering.
802     bool isLastReferenceCount() const { return mRefCount.load(std::memory_order_acquire) == 1; }
803 #else
804     // Compiler still compile but should never actually produce code.
805     bool isReferenced() const
806     {
807         UNREACHABLE();
808         return false;
809     }
810     uint32_t getRefCount() const
811     {
812         UNREACHABLE();
813         return 0;
814     }
815     bool isLastReferenceCount() const
816     {
817         UNREACHABLE();
818         return false;
819     }
820 #endif
821 
822     T &get() { return mObject; }
823     const T &get() const { return mObject; }
824 
825   private:
826     std::atomic_uint mRefCount;
827     T mObject;
828 };
829 
830 // This is intended to have same interface as std::shared_ptr except this must used in thread safe
831 // environment.
832 template <typename>
833 class WeakPtr;
834 template <typename T, class RefCountedStorage = RefCounted<T>>
835 class SharedPtr final
836 {
837   public:
838     SharedPtr() : mRefCounted(nullptr), mDevice(VK_NULL_HANDLE) {}
839     SharedPtr(VkDevice device, T &&object) : mDevice(device)
840     {
841         mRefCounted = new RefCountedStorage(std::move(object));
842         mRefCounted->addRef();
843     }
844     SharedPtr(VkDevice device, const WeakPtr<T> &other)
845         : mRefCounted(other.mRefCounted), mDevice(device)
846     {
847         if (mRefCounted)
848         {
849             // There must already have another SharedPtr holding onto the underline object when
850             // WeakPtr is valid.
851             ASSERT(mRefCounted->isReferenced());
852             mRefCounted->addRef();
853         }
854     }
855     ~SharedPtr() { reset(); }
856 
857     SharedPtr(const SharedPtr &other) : mRefCounted(nullptr), mDevice(VK_NULL_HANDLE)
858     {
859         *this = other;
860     }
861 
862     SharedPtr(SharedPtr &&other) : mRefCounted(nullptr), mDevice(VK_NULL_HANDLE)
863     {
864         *this = std::move(other);
865     }
866 
867     template <class... Args>
868     static SharedPtr<T, RefCountedStorage> MakeShared(VkDevice device, Args &&...args)
869     {
870         SharedPtr<T, RefCountedStorage> newObject;
871         newObject.mRefCounted = new RefCountedStorage(std::forward<Args>(args)...);
872         newObject.mRefCounted->addRef();
873         newObject.mDevice = device;
874         return newObject;
875     }
876 
877     void reset()
878     {
879         if (mRefCounted)
880         {
881             releaseRef();
882             mRefCounted = nullptr;
883             mDevice     = VK_NULL_HANDLE;
884         }
885     }
886 
887     SharedPtr &operator=(SharedPtr &&other)
888     {
889         if (mRefCounted)
890         {
891             releaseRef();
892         }
893         mRefCounted       = other.mRefCounted;
894         mDevice           = other.mDevice;
895         other.mRefCounted = nullptr;
896         other.mDevice     = VK_NULL_HANDLE;
897         return *this;
898     }
899 
900     SharedPtr &operator=(const SharedPtr &other)
901     {
902         if (mRefCounted)
903         {
904             releaseRef();
905         }
906         mRefCounted = other.mRefCounted;
907         mDevice     = other.mDevice;
908         if (mRefCounted)
909         {
910             mRefCounted->addRef();
911         }
912         return *this;
913     }
914 
915     operator bool() const { return mRefCounted != nullptr; }
916 
917     T &operator*() const
918     {
919         ASSERT(mRefCounted != nullptr);
920         return mRefCounted->get();
921     }
922 
923     T *operator->() const { return get(); }
924 
925     T *get() const
926     {
927         ASSERT(mRefCounted != nullptr);
928         return &mRefCounted->get();
929     }
930 
931     bool unique() const
932     {
933         ASSERT(mRefCounted != nullptr);
934         return mRefCounted->isLastReferenceCount();
935     }
936 
937     bool owner_equal(const SharedPtr<T> &other) const { return mRefCounted == other.mRefCounted; }
938 
939     uint32_t getRefCount() const { return mRefCounted->getRefCount(); }
940 
941   private:
942     void releaseRef()
943     {
944         ASSERT(mRefCounted != nullptr);
945         unsigned int refCount = mRefCounted->getAndReleaseRef();
946         if (refCount == 1)
947         {
948             mRefCounted->get().destroy(mDevice);
949             SafeDelete(mRefCounted);
950         }
951     }
952 
953     friend class WeakPtr<T>;
954     RefCountedStorage *mRefCounted;
955     VkDevice mDevice;
956 };
957 
958 template <typename T>
959 using AtomicSharedPtr = SharedPtr<T, AtomicRefCounted<T>>;
960 
961 // This is intended to have same interface as std::weak_ptr
962 template <typename T>
963 class WeakPtr final
964 {
965   public:
966     using RefCountedStorage = RefCounted<T>;
967 
968     WeakPtr() : mRefCounted(nullptr) {}
969 
970     WeakPtr(const SharedPtr<T> &other) : mRefCounted(other.mRefCounted) {}
971 
972     void reset() { mRefCounted = nullptr; }
973 
974     operator bool() const
975     {
976         // There must have another SharedPtr holding onto the underline object when WeakPtr is
977         // valid.
978         ASSERT(mRefCounted == nullptr || mRefCounted->isReferenced());
979         return mRefCounted != nullptr;
980     }
981 
982     T *operator->() const { return get(); }
983 
984     T *get() const
985     {
986         ASSERT(mRefCounted != nullptr);
987         ASSERT(mRefCounted->isReferenced());
988         return &mRefCounted->get();
989     }
990 
991     long use_count() const
992     {
993         ASSERT(mRefCounted != nullptr);
994         // There must have another SharedPtr holding onto the underline object when WeakPtr is
995         // valid.
996         ASSERT(mRefCounted->isReferenced());
997         return mRefCounted->getRefCount();
998     }
999     bool owner_equal(const SharedPtr<T> &other) const
1000     {
1001         // There must have another SharedPtr holding onto the underlying object when WeakPtr is
1002         // valid.
1003         ASSERT(mRefCounted == nullptr || mRefCounted->isReferenced());
1004         return mRefCounted == other.mRefCounted;
1005     }
1006 
1007   private:
1008     friend class SharedPtr<T>;
1009     RefCountedStorage *mRefCounted;
1010 };
1011 
1012 // Helper class to share ref-counted Vulkan objects.  Requires that T have a destroy method
1013 // that takes a VkDevice and returns void.
1014 template <typename T>
1015 class Shared final : angle::NonCopyable
1016 {
1017   public:
1018     Shared() : mRefCounted(nullptr) {}
1019     ~Shared() { ASSERT(mRefCounted == nullptr); }
1020 
1021     Shared(Shared &&other) { *this = std::move(other); }
1022     Shared &operator=(Shared &&other)
1023     {
1024         ASSERT(this != &other);
1025         mRefCounted       = other.mRefCounted;
1026         other.mRefCounted = nullptr;
1027         return *this;
1028     }
1029 
1030     void set(VkDevice device, RefCounted<T> *refCounted)
1031     {
1032         if (mRefCounted)
1033         {
1034             mRefCounted->releaseRef();
1035             if (!mRefCounted->isReferenced())
1036             {
1037                 mRefCounted->get().destroy(device);
1038                 SafeDelete(mRefCounted);
1039             }
1040         }
1041 
1042         mRefCounted = refCounted;
1043 
1044         if (mRefCounted)
1045         {
1046             mRefCounted->addRef();
1047         }
1048     }
1049 
1050     void setUnreferenced(RefCounted<T> *refCounted)
1051     {
1052         ASSERT(!mRefCounted);
1053         ASSERT(refCounted);
1054 
1055         mRefCounted = refCounted;
1056         mRefCounted->addRef();
1057     }
1058 
1059     void assign(VkDevice device, T &&newObject)
1060     {
1061         set(device, new RefCounted<T>(std::move(newObject)));
1062     }
1063 
1064     void copy(VkDevice device, const Shared<T> &other) { set(device, other.mRefCounted); }
1065 
1066     void copyUnreferenced(const Shared<T> &other) { setUnreferenced(other.mRefCounted); }
1067 
1068     void reset(VkDevice device) { set(device, nullptr); }
1069 
1070     template <typename RecyclerT>
1071     void resetAndRecycle(RecyclerT *recycler)
1072     {
1073         if (mRefCounted)
1074         {
1075             mRefCounted->releaseRef();
1076             if (!mRefCounted->isReferenced())
1077             {
1078                 ASSERT(mRefCounted->get().valid());
1079                 recycler->recycle(std::move(mRefCounted->get()));
1080                 SafeDelete(mRefCounted);
1081             }
1082 
1083             mRefCounted = nullptr;
1084         }
1085     }
1086 
1087     template <typename OnRelease>
1088     void resetAndRelease(OnRelease *onRelease)
1089     {
1090         if (mRefCounted)
1091         {
1092             mRefCounted->releaseRef();
1093             if (!mRefCounted->isReferenced())
1094             {
1095                 ASSERT(mRefCounted->get().valid());
1096                 (*onRelease)(std::move(mRefCounted->get()));
1097                 SafeDelete(mRefCounted);
1098             }
1099 
1100             mRefCounted = nullptr;
1101         }
1102     }
1103 
1104     bool isReferenced() const
1105     {
1106         // If reference is zero, the object should have been deleted.  I.e. if the object is not
1107         // nullptr, it should have a reference.
1108         ASSERT(!mRefCounted || mRefCounted->isReferenced());
1109         return mRefCounted != nullptr;
1110     }
1111 
1112     T &get()
1113     {
1114         ASSERT(mRefCounted && mRefCounted->isReferenced());
1115         return mRefCounted->get();
1116     }
1117     const T &get() const
1118     {
1119         ASSERT(mRefCounted && mRefCounted->isReferenced());
1120         return mRefCounted->get();
1121     }
1122 
1123   private:
1124     RefCounted<T> *mRefCounted;
1125 };
1126 
1127 template <typename T, typename StorageT = std::deque<T>>
1128 class Recycler final : angle::NonCopyable
1129 {
1130   public:
1131     Recycler() = default;
1132     Recycler(StorageT &&storage) { mObjectFreeList = std::move(storage); }
1133 
1134     void recycle(T &&garbageObject)
1135     {
1136         // Recycling invalid objects is pointless and potentially a bug.
1137         ASSERT(garbageObject.valid());
1138         mObjectFreeList.emplace_back(std::move(garbageObject));
1139     }
1140 
1141     void recycle(StorageT &&garbageObjects)
1142     {
1143         // Recycling invalid objects is pointless and potentially a bug.
1144         ASSERT(!garbageObjects.empty());
1145         mObjectFreeList.insert(mObjectFreeList.end(), garbageObjects.begin(), garbageObjects.end());
1146         ASSERT(garbageObjects.empty());
1147     }
1148 
1149     void refill(StorageT &&garbageObjects)
1150     {
1151         ASSERT(!garbageObjects.empty());
1152         ASSERT(mObjectFreeList.empty());
1153         mObjectFreeList.swap(garbageObjects);
1154     }
1155 
1156     void fetch(T *outObject)
1157     {
1158         ASSERT(!empty());
1159         *outObject = std::move(mObjectFreeList.back());
1160         mObjectFreeList.pop_back();
1161     }
1162 
1163     void destroy(VkDevice device)
1164     {
1165         while (!mObjectFreeList.empty())
1166         {
1167             T &object = mObjectFreeList.back();
1168             object.destroy(device);
1169             mObjectFreeList.pop_back();
1170         }
1171     }
1172 
1173     bool empty() const { return mObjectFreeList.empty(); }
1174 
1175   private:
1176     StorageT mObjectFreeList;
1177 };
1178 
1179 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
1180 struct SpecializationConstants final
1181 {
1182     VkBool32 surfaceRotation;
1183     uint32_t dither;
1184 };
1185 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
1186 
1187 template <typename T>
1188 using SpecializationConstantMap = angle::PackedEnumMap<sh::vk::SpecializationConstantId, T>;
1189 
1190 using ShaderModulePtr = SharedPtr<ShaderModule>;
1191 using ShaderModuleMap = gl::ShaderMap<ShaderModulePtr>;
1192 
1193 angle::Result InitShaderModule(Context *context,
1194                                ShaderModulePtr *shaderModulePtr,
1195                                const uint32_t *shaderCode,
1196                                size_t shaderCodeSize);
1197 
1198 void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label);
1199 
1200 constexpr size_t kUnpackedDepthIndex   = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1201 constexpr size_t kUnpackedStencilIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
1202 constexpr uint32_t kUnpackedColorBuffersMask =
1203     angle::BitMask<uint32_t>(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
1204 
1205 class ClearValuesArray final
1206 {
1207   public:
1208     ClearValuesArray();
1209     ~ClearValuesArray();
1210 
1211     ClearValuesArray(const ClearValuesArray &other);
1212     ClearValuesArray &operator=(const ClearValuesArray &rhs);
1213 
1214     void store(uint32_t index, VkImageAspectFlags aspectFlags, const VkClearValue &clearValue);
1215     void storeNoDepthStencil(uint32_t index, const VkClearValue &clearValue);
1216 
1217     void reset(size_t index)
1218     {
1219         mValues[index] = {};
1220         mEnabled.reset(index);
1221     }
1222 
1223     bool test(size_t index) const { return mEnabled.test(index); }
1224     bool testDepth() const { return mEnabled.test(kUnpackedDepthIndex); }
1225     bool testStencil() const { return mEnabled.test(kUnpackedStencilIndex); }
1226     gl::DrawBufferMask getColorMask() const;
1227 
1228     const VkClearValue &operator[](size_t index) const { return mValues[index]; }
1229 
1230     float getDepthValue() const { return mValues[kUnpackedDepthIndex].depthStencil.depth; }
1231     uint32_t getStencilValue() const { return mValues[kUnpackedStencilIndex].depthStencil.stencil; }
1232 
1233     const VkClearValue *data() const { return mValues.data(); }
1234     bool empty() const { return mEnabled.none(); }
1235     bool any() const { return mEnabled.any(); }
1236 
1237   private:
1238     gl::AttachmentArray<VkClearValue> mValues;
1239     gl::AttachmentsMask mEnabled;
1240 };
1241 
1242 // Defines Serials for Vulkan objects.
1243 #define ANGLE_VK_SERIAL_OP(X) \
1244     X(Buffer)                 \
1245     X(Image)                  \
1246     X(ImageOrBufferView)      \
1247     X(Sampler)
1248 
1249 #define ANGLE_DEFINE_VK_SERIAL_TYPE(Type)                                     \
1250     class Type##Serial                                                        \
1251     {                                                                         \
1252       public:                                                                 \
1253         constexpr Type##Serial() : mSerial(kInvalid) {}                       \
1254         constexpr explicit Type##Serial(uint32_t serial) : mSerial(serial) {} \
1255                                                                               \
1256         constexpr bool operator==(const Type##Serial &other) const            \
1257         {                                                                     \
1258             ASSERT(mSerial != kInvalid || other.mSerial != kInvalid);         \
1259             return mSerial == other.mSerial;                                  \
1260         }                                                                     \
1261         constexpr bool operator!=(const Type##Serial &other) const            \
1262         {                                                                     \
1263             ASSERT(mSerial != kInvalid || other.mSerial != kInvalid);         \
1264             return mSerial != other.mSerial;                                  \
1265         }                                                                     \
1266         constexpr uint32_t getValue() const                                   \
1267         {                                                                     \
1268             return mSerial;                                                   \
1269         }                                                                     \
1270         constexpr bool valid() const                                          \
1271         {                                                                     \
1272             return mSerial != kInvalid;                                       \
1273         }                                                                     \
1274                                                                               \
1275       private:                                                                \
1276         uint32_t mSerial;                                                     \
1277         static constexpr uint32_t kInvalid = 0;                               \
1278     };                                                                        \
1279     static constexpr Type##Serial kInvalid##Type##Serial = Type##Serial();
1280 
1281 ANGLE_VK_SERIAL_OP(ANGLE_DEFINE_VK_SERIAL_TYPE)
1282 
1283 #define ANGLE_DECLARE_GEN_VK_SERIAL(Type) Type##Serial generate##Type##Serial();
1284 
1285 class ResourceSerialFactory final : angle::NonCopyable
1286 {
1287   public:
1288     ResourceSerialFactory();
1289     ~ResourceSerialFactory();
1290 
1291     ANGLE_VK_SERIAL_OP(ANGLE_DECLARE_GEN_VK_SERIAL)
1292 
1293   private:
1294     uint32_t issueSerial();
1295 
1296     // Kept atomic so it can be accessed from multiple Context threads at once.
1297     std::atomic<uint32_t> mCurrentUniqueSerial;
1298 };
1299 
1300 #if defined(ANGLE_ENABLE_PERF_COUNTER_OUTPUT)
1301 constexpr bool kOutputCumulativePerfCounters = ANGLE_ENABLE_PERF_COUNTER_OUTPUT;
1302 #else
1303 constexpr bool kOutputCumulativePerfCounters = false;
1304 #endif
1305 
1306 // Performance and resource counters.
1307 struct RenderPassPerfCounters
1308 {
1309     // load/storeOps. Includes ops for resolve attachment. Maximum value = 2.
1310     uint8_t colorLoadOpClears;
1311     uint8_t colorLoadOpLoads;
1312     uint8_t colorLoadOpNones;
1313     uint8_t colorStoreOpStores;
1314     uint8_t colorStoreOpNones;
1315     uint8_t depthLoadOpClears;
1316     uint8_t depthLoadOpLoads;
1317     uint8_t depthLoadOpNones;
1318     uint8_t depthStoreOpStores;
1319     uint8_t depthStoreOpNones;
1320     uint8_t stencilLoadOpClears;
1321     uint8_t stencilLoadOpLoads;
1322     uint8_t stencilLoadOpNones;
1323     uint8_t stencilStoreOpStores;
1324     uint8_t stencilStoreOpNones;
1325     // Number of unresolve and resolve operations.  Maximum value for color =
1326     // gl::IMPLEMENTATION_MAX_DRAW_BUFFERS and for depth/stencil = 1 each.
1327     uint8_t colorAttachmentUnresolves;
1328     uint8_t colorAttachmentResolves;
1329     uint8_t depthAttachmentUnresolves;
1330     uint8_t depthAttachmentResolves;
1331     uint8_t stencilAttachmentUnresolves;
1332     uint8_t stencilAttachmentResolves;
1333     // Whether the depth/stencil attachment is using a read-only layout.
1334     uint8_t readOnlyDepthStencil;
1335 };
1336 
1337 // A Vulkan image level index.
1338 using LevelIndex = gl::LevelIndexWrapper<uint32_t>;
1339 
1340 // Ensure viewport is within Vulkan requirements
1341 void ClampViewport(VkViewport *viewport);
1342 
1343 constexpr bool IsDynamicDescriptor(VkDescriptorType descriptorType)
1344 {
1345     switch (descriptorType)
1346     {
1347         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1348         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
1349             return true;
1350         default:
1351             return false;
1352     }
1353 }
1354 
1355 void ApplyPipelineCreationFeedback(Context *context, const VkPipelineCreationFeedback &feedback);
1356 
1357 angle::Result SetDebugUtilsObjectName(ContextVk *contextVk,
1358                                       VkObjectType objectType,
1359                                       uint64_t handle,
1360                                       const std::string &label);
1361 
1362 }  // namespace vk
1363 
1364 #if !defined(ANGLE_SHARED_LIBVULKAN)
1365 // Lazily load entry points for each extension as necessary.
1366 void InitDebugUtilsEXTFunctions(VkInstance instance);
1367 void InitTransformFeedbackEXTFunctions(VkDevice device);
1368 void InitRenderPass2KHRFunctions(VkDevice device);
1369 
1370 #    if defined(ANGLE_PLATFORM_FUCHSIA)
1371 // VK_FUCHSIA_imagepipe_surface
1372 void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance);
1373 #    endif
1374 
1375 #    if defined(ANGLE_PLATFORM_ANDROID)
1376 // VK_ANDROID_external_memory_android_hardware_buffer
1377 void InitExternalMemoryHardwareBufferANDROIDFunctions(VkDevice device);
1378 #    endif
1379 
1380 #    if defined(ANGLE_PLATFORM_GGP)
1381 // VK_GGP_stream_descriptor_surface
1382 void InitGGPStreamDescriptorSurfaceFunctions(VkInstance instance);
1383 #    endif  // defined(ANGLE_PLATFORM_GGP)
1384 
1385 // VK_KHR_external_semaphore_fd
1386 void InitExternalSemaphoreFdFunctions(VkDevice device);
1387 
1388 // VK_EXT_host_query_reset
1389 void InitHostQueryResetFunctions(VkDevice device);
1390 
1391 // VK_KHR_external_fence_fd
1392 void InitExternalFenceFdFunctions(VkDevice device);
1393 
1394 // VK_KHR_shared_presentable_image
1395 void InitGetSwapchainStatusKHRFunctions(VkDevice device);
1396 
1397 // VK_EXT_extended_dynamic_state
1398 void InitExtendedDynamicStateEXTFunctions(VkDevice device);
1399 
1400 // VK_EXT_extended_dynamic_state2
1401 void InitExtendedDynamicState2EXTFunctions(VkDevice device);
1402 
1403 // VK_EXT_vertex_input_dynamic_state
1404 void InitVertexInputDynamicStateEXTFunctions(VkDevice device);
1405 
1406 // VK_KHR_dynamic_rendering
1407 void InitDynamicRenderingFunctions(VkDevice device);
1408 
1409 // VK_KHR_dynamic_rendering_local_read
1410 void InitDynamicRenderingLocalReadFunctions(VkDevice device);
1411 
1412 // VK_KHR_fragment_shading_rate
1413 void InitFragmentShadingRateKHRInstanceFunction(VkInstance instance);
1414 void InitFragmentShadingRateKHRDeviceFunction(VkDevice device);
1415 
1416 // VK_GOOGLE_display_timing
1417 void InitGetPastPresentationTimingGoogleFunction(VkDevice device);
1418 
1419 // VK_EXT_host_image_copy
1420 void InitHostImageCopyFunctions(VkDevice device);
1421 
1422 // VK_KHR_Synchronization2
1423 void InitSynchronization2Functions(VkDevice device);
1424 
1425 #endif  // !defined(ANGLE_SHARED_LIBVULKAN)
1426 
1427 // Promoted to Vulkan 1.1
1428 void InitGetPhysicalDeviceProperties2KHRFunctionsFromCore();
1429 void InitExternalFenceCapabilitiesFunctionsFromCore();
1430 void InitExternalSemaphoreCapabilitiesFunctionsFromCore();
1431 void InitSamplerYcbcrKHRFunctionsFromCore();
1432 void InitGetMemoryRequirements2KHRFunctionsFromCore();
1433 void InitBindMemory2KHRFunctionsFromCore();
1434 
1435 GLenum CalculateGenerateMipmapFilter(ContextVk *contextVk, angle::FormatID formatID);
1436 
1437 namespace gl_vk
1438 {
1439 VkRect2D GetRect(const gl::Rectangle &source);
1440 VkFilter GetFilter(const GLenum filter);
1441 VkSamplerMipmapMode GetSamplerMipmapMode(const GLenum filter);
1442 VkSamplerAddressMode GetSamplerAddressMode(const GLenum wrap);
1443 VkPrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode);
1444 VkPolygonMode GetPolygonMode(const gl::PolygonMode polygonMode);
1445 VkCullModeFlagBits GetCullMode(const gl::RasterizerState &rasterState);
1446 VkFrontFace GetFrontFace(GLenum frontFace, bool invertCullFace);
1447 VkSampleCountFlagBits GetSamples(GLint sampleCount, bool limitSampleCountTo2);
1448 VkComponentSwizzle GetSwizzle(const GLenum swizzle);
1449 VkCompareOp GetCompareOp(const GLenum compareFunc);
1450 VkStencilOp GetStencilOp(const GLenum compareOp);
1451 VkLogicOp GetLogicOp(const GLenum logicOp);
1452 
1453 constexpr gl::ShaderMap<VkShaderStageFlagBits> kShaderStageMap = {
1454     {gl::ShaderType::Vertex, VK_SHADER_STAGE_VERTEX_BIT},
1455     {gl::ShaderType::TessControl, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT},
1456     {gl::ShaderType::TessEvaluation, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT},
1457     {gl::ShaderType::Fragment, VK_SHADER_STAGE_FRAGMENT_BIT},
1458     {gl::ShaderType::Geometry, VK_SHADER_STAGE_GEOMETRY_BIT},
1459     {gl::ShaderType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
1460 };
1461 
1462 void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
1463 void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
1464 VkImageType GetImageType(gl::TextureType textureType);
1465 VkImageViewType GetImageViewType(gl::TextureType textureType);
1466 VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
1467 VkShaderStageFlags GetShaderStageFlags(gl::ShaderBitSet activeShaders);
1468 
1469 void GetViewport(const gl::Rectangle &viewport,
1470                  float nearPlane,
1471                  float farPlane,
1472                  bool invertViewport,
1473                  bool upperLeftOrigin,
1474                  GLint renderAreaHeight,
1475                  VkViewport *viewportOut);
1476 
1477 void GetExtentsAndLayerCount(gl::TextureType textureType,
1478                              const gl::Extents &extents,
1479                              VkExtent3D *extentsOut,
1480                              uint32_t *layerCountOut);
1481 
1482 vk::LevelIndex GetLevelIndex(gl::LevelIndex levelGL, gl::LevelIndex baseLevel);
1483 
1484 VkImageTiling GetTilingMode(gl::TilingMode tilingMode);
1485 
1486 }  // namespace gl_vk
1487 
1488 namespace vk_gl
1489 {
1490 // The Vulkan back-end will not support a sample count of 1, because of a Vulkan specification
1491 // restriction:
1492 //
1493 //   If the image was created with VkImageCreateInfo::samples equal to VK_SAMPLE_COUNT_1_BIT, the
1494 //   instruction must: have MS = 0.
1495 //
1496 // This restriction was tracked in http://anglebug.com/42262827 and Khronos-private Vulkan
1497 // specification issue https://gitlab.khronos.org/vulkan/vulkan/issues/1925.
1498 //
1499 // In addition, the Vulkan back-end will not support sample counts of 32 or 64, since there are no
1500 // standard sample locations for those sample counts.
1501 constexpr unsigned int kSupportedSampleCounts = (VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT |
1502                                                  VK_SAMPLE_COUNT_8_BIT | VK_SAMPLE_COUNT_16_BIT);
1503 
1504 // Find set bits in sampleCounts and add the corresponding sample count to the set.
1505 void AddSampleCounts(VkSampleCountFlags sampleCounts, gl::SupportedSampleSet *outSet);
1506 // Return the maximum sample count with a bit set in |sampleCounts|.
1507 GLuint GetMaxSampleCount(VkSampleCountFlags sampleCounts);
1508 // Return a supported sample count that's at least as large as the requested one.
1509 GLuint GetSampleCount(VkSampleCountFlags supportedCounts, GLuint requestedCount);
1510 
1511 gl::LevelIndex GetLevelIndex(vk::LevelIndex levelVk, gl::LevelIndex baseLevel);
1512 
1513 GLenum ConvertVkFixedRateToGLFixedRate(const VkImageCompressionFixedRateFlagsEXT vkCompressionRate);
1514 GLint convertCompressionFlagsToGLFixedRates(
1515     VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags,
1516     GLsizei bufSize,
1517     GLint *rates);
1518 }  // namespace vk_gl
1519 
1520 enum class RenderPassClosureReason
1521 {
1522     // Don't specify the reason (it should already be specified elsewhere)
1523     AlreadySpecifiedElsewhere,
1524 
1525     // Implicit closures due to flush/wait/etc.
1526     ContextDestruction,
1527     ContextChange,
1528     GLFlush,
1529     GLFinish,
1530     EGLSwapBuffers,
1531     EGLWaitClient,
1532     SurfaceUnMakeCurrent,
1533 
1534     // Closure due to switching rendering to another framebuffer.
1535     FramebufferBindingChange,
1536     FramebufferChange,
1537     NewRenderPass,
1538 
1539     // Incompatible use of resource in the same render pass
1540     BufferUseThenXfbWrite,
1541     XfbWriteThenVertexIndexBuffer,
1542     XfbWriteThenIndirectDrawBuffer,
1543     XfbResumeAfterDrawBasedClear,
1544     DepthStencilUseInFeedbackLoop,
1545     DepthStencilWriteAfterFeedbackLoop,
1546     PipelineBindWhileXfbActive,
1547 
1548     // Use of resource after render pass
1549     BufferWriteThenMap,
1550     BufferWriteThenOutOfRPRead,
1551     BufferUseThenOutOfRPWrite,
1552     ImageUseThenOutOfRPRead,
1553     ImageUseThenOutOfRPWrite,
1554     XfbWriteThenComputeRead,
1555     XfbWriteThenIndirectDispatchBuffer,
1556     ImageAttachmentThenComputeRead,
1557     GraphicsTextureImageAccessThenComputeAccess,
1558     GetQueryResult,
1559     BeginNonRenderPassQuery,
1560     EndNonRenderPassQuery,
1561     TimestampQuery,
1562     EndRenderPassQuery,
1563     GLReadPixels,
1564 
1565     // Synchronization
1566     BufferUseThenReleaseToExternal,
1567     ImageUseThenReleaseToExternal,
1568     BufferInUseWhenSynchronizedMap,
1569     GLMemoryBarrierThenStorageResource,
1570     StorageResourceUseThenGLMemoryBarrier,
1571     ExternalSemaphoreSignal,
1572     SyncObjectInit,
1573     SyncObjectWithFdInit,
1574     SyncObjectClientWait,
1575     SyncObjectServerWait,
1576     SyncObjectGetStatus,
1577 
1578     // Closures that ANGLE could have avoided, but doesn't for simplicity or optimization of more
1579     // common cases.
1580     XfbPause,
1581     FramebufferFetchEmulation,
1582     GenerateMipmapOnCPU,
1583     CopyTextureOnCPU,
1584     TextureReformatToRenderable,
1585     DeviceLocalBufferMap,
1586     OutOfReservedQueueSerialForOutsideCommands,
1587 
1588     // UtilsVk
1589     GenerateMipmapWithDraw,
1590     PrepareForBlit,
1591     PrepareForImageCopy,
1592     TemporaryForClearTexture,
1593     TemporaryForImageClear,
1594     TemporaryForImageCopy,
1595     TemporaryForOverlayDraw,
1596 
1597     // LegacyDithering requires updating the render pass
1598     LegacyDithering,
1599 
1600     // In case of memory budget issues, pending garbage needs to be freed.
1601     ExcessivePendingGarbage,
1602     OutOfMemory,
1603 
1604     InvalidEnum,
1605     EnumCount = InvalidEnum,
1606 };
1607 
1608 // The scope of synchronization for a sync object.  Synchronization is done between the signal
1609 // entity (src) and the entities waiting on the signal (dst)
1610 //
1611 // - For GL fence sync objects, src is the current context and dst is host / the rest of share
1612 // group.
1613 // - For EGL fence sync objects, src is the current context and dst is host / all other contexts.
1614 // - For EGL global fence sync objects (which is an ANGLE extension), src is all contexts who have
1615 //   previously made a submission to the queue used by the current context and dst is host / all
1616 //   other contexts.
1617 enum class SyncFenceScope
1618 {
1619     CurrentContextToShareGroup,
1620     CurrentContextToAllContexts,
1621     AllContextsToAllContexts,
1622 };
1623 
1624 }  // namespace rx
1625 
1626 #define ANGLE_VK_TRY(context, command)                                                   \
1627     do                                                                                   \
1628     {                                                                                    \
1629         auto ANGLE_LOCAL_VAR = command;                                                  \
1630         if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR != VK_SUCCESS))                               \
1631         {                                                                                \
1632             (context)->handleError(ANGLE_LOCAL_VAR, __FILE__, ANGLE_FUNCTION, __LINE__); \
1633             return angle::Result::Stop;                                                  \
1634         }                                                                                \
1635     } while (0)
1636 
1637 #define ANGLE_VK_CHECK(context, test, error) ANGLE_VK_TRY(context, test ? VK_SUCCESS : error)
1638 
1639 #define ANGLE_VK_CHECK_MATH(context, result) \
1640     ANGLE_VK_CHECK(context, result, VK_ERROR_VALIDATION_FAILED_EXT)
1641 
1642 #define ANGLE_VK_CHECK_ALLOC(context, result) \
1643     ANGLE_VK_CHECK(context, result, VK_ERROR_OUT_OF_HOST_MEMORY)
1644 
1645 #define ANGLE_VK_UNREACHABLE(context) \
1646     UNREACHABLE();                    \
1647     ANGLE_VK_CHECK(context, false, VK_ERROR_FEATURE_NOT_PRESENT)
1648 
1649 // Returns VkResult in the case of an error.
1650 #define VK_RESULT_TRY(command)                             \
1651     do                                                     \
1652     {                                                      \
1653         auto ANGLE_LOCAL_VAR = command;                    \
1654         if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR != VK_SUCCESS)) \
1655         {                                                  \
1656             return ANGLE_LOCAL_VAR;                        \
1657         }                                                  \
1658     } while (0)
1659 
1660 #define VK_RESULT_CHECK(test, error) VK_RESULT_TRY((test) ? VK_SUCCESS : (error))
1661 
1662 // NVIDIA uses special formatting for the driver version:
1663 // Major: 10
1664 // Minor: 8
1665 // Sub-minor: 8
1666 // patch: 6
1667 #define ANGLE_VK_VERSION_MAJOR_NVIDIA(version) (((uint32_t)(version) >> 22) & 0x3ff)
1668 #define ANGLE_VK_VERSION_MINOR_NVIDIA(version) (((uint32_t)(version) >> 14) & 0xff)
1669 #define ANGLE_VK_VERSION_SUB_MINOR_NVIDIA(version) (((uint32_t)(version) >> 6) & 0xff)
1670 #define ANGLE_VK_VERSION_PATCH_NVIDIA(version) ((uint32_t)(version) & 0x3f)
1671 
1672 // Similarly for Intel on Windows:
1673 // Major: 18
1674 // Minor: 14
1675 #define ANGLE_VK_VERSION_MAJOR_WIN_INTEL(version) (((uint32_t)(version) >> 14) & 0x3ffff)
1676 #define ANGLE_VK_VERSION_MINOR_WIN_INTEL(version) ((uint32_t)(version) & 0x3fff)
1677 
1678 #endif  // LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
1679