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 &©) : mRefCount(copy.mRefCount), mObject(std::move(copy.mObject))
715 {
716 ASSERT(this != ©);
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