• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <limits>
14 
15 #include "common/FixedVector.h"
16 #include "common/Optional.h"
17 #include "common/PackedEnums.h"
18 #include "common/debug.h"
19 #include "libANGLE/Error.h"
20 #include "libANGLE/Observer.h"
21 #include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
22 #include "libANGLE/renderer/vulkan/vk_wrapper.h"
23 
24 #define ANGLE_GL_OBJECTS_X(PROC) \
25     PROC(Buffer)                 \
26     PROC(Context)                \
27     PROC(Framebuffer)            \
28     PROC(MemoryObject)           \
29     PROC(Query)                  \
30     PROC(Program)                \
31     PROC(Sampler)                \
32     PROC(Semaphore)              \
33     PROC(Texture)                \
34     PROC(TransformFeedback)      \
35     PROC(VertexArray)
36 
37 #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
38 
39 namespace egl
40 {
41 class Display;
42 class Image;
43 }  // namespace egl
44 
45 namespace gl
46 {
47 struct Box;
48 struct Extents;
49 struct RasterizerState;
50 struct Rectangle;
51 class State;
52 struct SwizzleState;
53 struct VertexAttribute;
54 class VertexBinding;
55 
56 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT)
57 }  // namespace gl
58 
59 #define ANGLE_PRE_DECLARE_VK_OBJECT(OBJ) class OBJ##Vk;
60 
61 namespace rx
62 {
63 class CommandGraphResource;
64 class DisplayVk;
65 class ImageVk;
66 class RenderTargetVk;
67 class RendererVk;
68 class RenderPassCache;
69 }  // namespace rx
70 
71 namespace angle
72 {
73 egl::Error ToEGL(Result result, rx::DisplayVk *displayVk, EGLint errorCode);
74 }  // namespace angle
75 
76 namespace rx
77 {
78 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_VK_OBJECT)
79 
80 const char *VulkanResultString(VkResult result);
81 
82 constexpr size_t kMaxVulkanLayers = 20;
83 using VulkanLayerVector           = angle::FixedVector<const char *, kMaxVulkanLayers>;
84 
85 // Verify that validation layers are available.
86 bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerProps,
87                                   bool mustHaveLayers,
88                                   VulkanLayerVector *enabledLayerNames);
89 
90 extern const char *g_VkLoaderLayersPathEnv;
91 extern const char *g_VkICDPathEnv;
92 
93 enum class TextureDimension
94 {
95     TEX_2D,
96     TEX_CUBE,
97     TEX_3D,
98     TEX_2D_ARRAY,
99 };
100 
101 namespace vk
102 {
103 struct Format;
104 
105 // Abstracts error handling. Implemented by both ContextVk for GL and DisplayVk for EGL errors.
106 class Context : angle::NonCopyable
107 {
108   public:
109     Context(RendererVk *renderer);
110     virtual ~Context();
111 
112     virtual void handleError(VkResult result,
113                              const char *file,
114                              const char *function,
115                              unsigned int line) = 0;
116     VkDevice getDevice() const;
getRenderer()117     RendererVk *getRenderer() const { return mRenderer; }
118 
119   protected:
120     RendererVk *const mRenderer;
121 };
122 
123 #if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
124 using CommandBuffer = priv::SecondaryCommandBuffer;
125 #else
126 using CommandBuffer = priv::CommandBuffer;
127 #endif
128 
129 using PrimaryCommandBuffer = priv::CommandBuffer;
130 
131 VkImageAspectFlags GetDepthStencilAspectFlags(const angle::Format &format);
132 VkImageAspectFlags GetFormatAspectFlags(const angle::Format &format);
133 
134 template <typename T>
135 struct ImplTypeHelper;
136 
137 // clang-format off
138 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
139 template<>                             \
140 struct ImplTypeHelper<gl::OBJ>         \
141 {                                      \
142     using ImplType = OBJ##Vk;          \
143 };
144 // clang-format on
145 
146 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
147 
148 template <>
149 struct ImplTypeHelper<egl::Display>
150 {
151     using ImplType = DisplayVk;
152 };
153 
154 template <>
155 struct ImplTypeHelper<egl::Image>
156 {
157     using ImplType = ImageVk;
158 };
159 
160 template <typename T>
161 using GetImplType = typename ImplTypeHelper<T>::ImplType;
162 
163 template <typename T>
164 GetImplType<T> *GetImpl(const T *glObject)
165 {
166     return GetImplAs<GetImplType<T>>(glObject);
167 }
168 
169 class GarbageObjectBase
170 {
171   public:
172     template <typename ObjectT>
173     GarbageObjectBase(const ObjectT &object)
174         : mHandleType(HandleTypeHelper<ObjectT>::kHandleType),
175           mHandle(reinterpret_cast<VkDevice>(object.getHandle()))
176     {}
177     GarbageObjectBase();
178 
179     void destroy(VkDevice device);
180 
181   private:
182     HandleType mHandleType;
183     VkDevice mHandle;
184 };
185 
186 class GarbageObject final : public GarbageObjectBase
187 {
188   public:
189     template <typename ObjectT>
190     GarbageObject(Serial serial, const ObjectT &object) : GarbageObjectBase(object), mSerial(serial)
191     {}
192 
193     GarbageObject();
194     GarbageObject(const GarbageObject &other);
195     GarbageObject &operator=(const GarbageObject &other);
196 
197     bool destroyIfComplete(VkDevice device, Serial completedSerial);
198 
199   private:
200     // TODO(jmadill): Since many objects will have the same serial, it might be more efficient to
201     // store the serial outside of the garbage object itself. We could index ranges of garbage
202     // objects in the Renderer, using a circular buffer.
203     Serial mSerial;
204 };
205 
206 class MemoryProperties final : angle::NonCopyable
207 {
208   public:
209     MemoryProperties();
210 
211     void init(VkPhysicalDevice physicalDevice);
212     angle::Result findCompatibleMemoryIndex(Context *context,
213                                             const VkMemoryRequirements &memoryRequirements,
214                                             VkMemoryPropertyFlags requestedMemoryPropertyFlags,
215                                             VkMemoryPropertyFlags *memoryPropertyFlagsOut,
216                                             uint32_t *indexOut) const;
217     void destroy();
218 
219   private:
220     VkPhysicalDeviceMemoryProperties mMemoryProperties;
221 };
222 
223 // Similar to StagingImage, for Buffers.
224 class StagingBuffer final : angle::NonCopyable
225 {
226   public:
227     StagingBuffer();
228     void destroy(VkDevice device);
229 
230     angle::Result init(Context *context, VkDeviceSize size, StagingUsage usage);
231 
232     Buffer &getBuffer() { return mBuffer; }
233     const Buffer &getBuffer() const { return mBuffer; }
234     DeviceMemory &getDeviceMemory() { return mDeviceMemory; }
235     const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
236     size_t getSize() const { return mSize; }
237 
238     void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue);
239 
240   private:
241     Buffer mBuffer;
242     DeviceMemory mDeviceMemory;
243     size_t mSize;
244 };
245 
246 template <typename ObjT>
247 class ObjectAndSerial final : angle::NonCopyable
248 {
249   public:
250     ObjectAndSerial() {}
251 
252     ObjectAndSerial(ObjT &&object, Serial serial) : mObject(std::move(object)), mSerial(serial) {}
253 
254     ObjectAndSerial(ObjectAndSerial &&other)
255         : mObject(std::move(other.mObject)), mSerial(std::move(other.mSerial))
256     {}
257     ObjectAndSerial &operator=(ObjectAndSerial &&other)
258     {
259         mObject = std::move(other.mObject);
260         mSerial = std::move(other.mSerial);
261         return *this;
262     }
263 
264     Serial getSerial() const { return mSerial; }
265     void updateSerial(Serial newSerial) { mSerial = newSerial; }
266 
267     const ObjT &get() const { return mObject; }
268     ObjT &get() { return mObject; }
269 
270     bool valid() const { return mObject.valid(); }
271 
272     void destroy(VkDevice device)
273     {
274         mObject.destroy(device);
275         mSerial = Serial();
276     }
277 
278   private:
279     ObjT mObject;
280     Serial mSerial;
281 };
282 
283 angle::Result AllocateBufferMemory(vk::Context *context,
284                                    VkMemoryPropertyFlags requestedMemoryPropertyFlags,
285                                    VkMemoryPropertyFlags *memoryPropertyFlagsOut,
286                                    const void *extraAllocationInfo,
287                                    Buffer *buffer,
288                                    DeviceMemory *deviceMemoryOut);
289 
290 angle::Result AllocateImageMemory(vk::Context *context,
291                                   VkMemoryPropertyFlags memoryPropertyFlags,
292                                   const void *extraAllocationInfo,
293                                   Image *image,
294                                   DeviceMemory *deviceMemoryOut);
295 angle::Result AllocateImageMemoryWithRequirements(vk::Context *context,
296                                                   VkMemoryPropertyFlags memoryPropertyFlags,
297                                                   const VkMemoryRequirements &memoryRequirements,
298                                                   const void *extraAllocationInfo,
299                                                   Image *image,
300                                                   DeviceMemory *deviceMemoryOut);
301 
302 using ShaderAndSerial = ObjectAndSerial<ShaderModule>;
303 
304 angle::Result InitShaderAndSerial(Context *context,
305                                   ShaderAndSerial *shaderAndSerial,
306                                   const uint32_t *shaderCode,
307                                   size_t shaderCodeSize);
308 
309 gl::TextureType Get2DTextureType(uint32_t layerCount, GLint samples);
310 
311 enum class RecordingMode
312 {
313     Start,
314     Append,
315 };
316 
317 // Helper class to handle RAII patterns for initialization. Requires that T have a destroy method
318 // that takes a VkDevice and returns void.
319 template <typename T>
320 class Scoped final : angle::NonCopyable
321 {
322   public:
323     Scoped(VkDevice device) : mDevice(device) {}
324     ~Scoped() { mVar.destroy(mDevice); }
325 
326     const T &get() const { return mVar; }
327     T &get() { return mVar; }
328 
329     T &&release() { return std::move(mVar); }
330 
331   private:
332     VkDevice mDevice;
333     T mVar;
334 };
335 
336 // This is a very simple RefCount class that has no autoreleasing. Used in the descriptor set and
337 // pipeline layout caches.
338 template <typename T>
339 class RefCounted : angle::NonCopyable
340 {
341   public:
342     RefCounted() : mRefCount(0) {}
343     explicit RefCounted(T &&newObject) : mRefCount(0), mObject(std::move(newObject)) {}
344     ~RefCounted() { ASSERT(mRefCount == 0 && !mObject.valid()); }
345 
346     RefCounted(RefCounted &&copy) : mRefCount(copy.mRefCount), mObject(std::move(copy.mObject))
347     {
348         ASSERT(this != &copy);
349         copy.mRefCount = 0;
350     }
351 
352     RefCounted &operator=(RefCounted &&rhs)
353     {
354         std::swap(mRefCount, rhs.mRefCount);
355         mObject = std::move(rhs.mObject);
356         return *this;
357     }
358 
359     void addRef()
360     {
361         ASSERT(mRefCount != std::numeric_limits<uint32_t>::max());
362         mRefCount++;
363     }
364 
365     void releaseRef()
366     {
367         ASSERT(isReferenced());
368         mRefCount--;
369     }
370 
371     bool isReferenced() const { return mRefCount != 0; }
372 
373     T &get() { return mObject; }
374     const T &get() const { return mObject; }
375 
376   private:
377     uint32_t mRefCount;
378     T mObject;
379 };
380 
381 template <typename T>
382 class BindingPointer final : angle::NonCopyable
383 {
384   public:
385     BindingPointer() : mRefCounted(nullptr) {}
386 
387     ~BindingPointer() { reset(); }
388 
389     void set(RefCounted<T> *refCounted)
390     {
391         if (mRefCounted)
392         {
393             mRefCounted->releaseRef();
394         }
395 
396         mRefCounted = refCounted;
397 
398         if (mRefCounted)
399         {
400             mRefCounted->addRef();
401         }
402     }
403 
404     void reset() { set(nullptr); }
405 
406     T &get() { return mRefCounted->get(); }
407     const T &get() const { return mRefCounted->get(); }
408 
409     bool valid() const { return mRefCounted != nullptr; }
410 
411   private:
412     RefCounted<T> *mRefCounted;
413 };
414 
415 // Helper class to share ref-counted Vulkan objects.  Requires that T have a destroy method
416 // that takes a VkDevice and returns void.
417 template <typename T>
418 class Shared final : angle::NonCopyable
419 {
420   public:
421     Shared() : mRefCounted(nullptr) {}
422     ~Shared() { ASSERT(mRefCounted == nullptr); }
423 
424     Shared(Shared &&other) { *this = std::move(other); }
425     Shared &operator=(Shared &&other)
426     {
427         ASSERT(this != &other);
428         mRefCounted       = other.mRefCounted;
429         other.mRefCounted = nullptr;
430         return *this;
431     }
432 
433     void set(VkDevice device, RefCounted<T> *refCounted)
434     {
435         if (mRefCounted)
436         {
437             mRefCounted->releaseRef();
438             if (!mRefCounted->isReferenced())
439             {
440                 mRefCounted->get().destroy(device);
441                 SafeDelete(mRefCounted);
442             }
443         }
444 
445         mRefCounted = refCounted;
446 
447         if (mRefCounted)
448         {
449             mRefCounted->addRef();
450         }
451     }
452 
453     void assign(VkDevice device, T &&newObject)
454     {
455         set(device, new RefCounted<T>(std::move(newObject)));
456     }
457 
458     void copy(VkDevice device, const Shared<T> &other) { set(device, other.mRefCounted); }
459 
460     void reset(VkDevice device) { set(device, nullptr); }
461 
462     template <typename RecyclerT>
463     void resetAndRecycle(RecyclerT *recycler)
464     {
465         if (mRefCounted)
466         {
467             mRefCounted->releaseRef();
468             if (!mRefCounted->isReferenced())
469             {
470                 ASSERT(mRefCounted->get().valid());
471                 recycler->recyle(std::move(mRefCounted->get()));
472                 SafeDelete(mRefCounted);
473             }
474 
475             mRefCounted = nullptr;
476         }
477     }
478 
479     bool isReferenced() const
480     {
481         // If reference is zero, the object should have been deleted.  I.e. if the object is not
482         // nullptr, it should have a reference.
483         ASSERT(!mRefCounted || mRefCounted->isReferenced());
484         return mRefCounted != nullptr;
485     }
486 
487     T &get()
488     {
489         ASSERT(mRefCounted && mRefCounted->isReferenced());
490         return mRefCounted->get();
491     }
492     const T &get() const
493     {
494         ASSERT(mRefCounted && mRefCounted->isReferenced());
495         return mRefCounted->get();
496     }
497 
498   private:
499     RefCounted<T> *mRefCounted;
500 };
501 
502 template <typename T>
503 class Recycler final : angle::NonCopyable
504 {
505   public:
506     Recycler() = default;
507 
508     void recyle(T &&garbageObject) { mObjectFreeList.emplace_back(std::move(garbageObject)); }
509 
510     void fetch(VkDevice device, T *outObject)
511     {
512         ASSERT(!empty());
513         *outObject = std::move(mObjectFreeList.back());
514         mObjectFreeList.pop_back();
515     }
516 
517     void destroy(VkDevice device)
518     {
519         for (T &object : mObjectFreeList)
520         {
521             object.destroy(device);
522         }
523     }
524 
525     bool empty() const { return mObjectFreeList.empty(); }
526 
527   private:
528     std::vector<T> mObjectFreeList;
529 };
530 
531 }  // namespace vk
532 
533 // List of function pointers for used extensions.
534 // VK_EXT_debug_utils
535 extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
536 extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
537 extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
538 extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
539 extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT;
540 
541 // VK_EXT_debug_report
542 extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
543 extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
544 
545 // VK_KHR_get_physical_device_properties2
546 extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
547 
548 // VK_KHR_external_semaphore_fd
549 extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR;
550 
551 // Lazily load entry points for each extension as necessary.
552 void InitDebugUtilsEXTFunctions(VkInstance instance);
553 void InitDebugReportEXTFunctions(VkInstance instance);
554 void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance);
555 
556 #if defined(ANGLE_PLATFORM_FUCHSIA)
557 // VK_FUCHSIA_imagepipe_surface
558 extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA;
559 void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance);
560 #endif
561 
562 #if defined(ANGLE_PLATFORM_ANDROID)
563 // VK_ANDROID_external_memory_android_hardware_buffer
564 extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID;
565 extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID;
566 void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance);
567 #endif
568 
569 void InitExternalSemaphoreFdFunctions(VkInstance instance);
570 
571 namespace gl_vk
572 {
573 VkRect2D GetRect(const gl::Rectangle &source);
574 VkFilter GetFilter(const GLenum filter);
575 VkSamplerMipmapMode GetSamplerMipmapMode(const GLenum filter);
576 VkSamplerAddressMode GetSamplerAddressMode(const GLenum wrap);
577 VkPrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode);
578 VkCullModeFlagBits GetCullMode(const gl::RasterizerState &rasterState);
579 VkFrontFace GetFrontFace(GLenum frontFace, bool invertCullFace);
580 VkSampleCountFlagBits GetSamples(GLint sampleCount);
581 VkComponentSwizzle GetSwizzle(const GLenum swizzle);
582 VkCompareOp GetCompareOp(const GLenum compareFunc);
583 
584 constexpr angle::PackedEnumMap<gl::DrawElementsType, VkIndexType> kIndexTypeMap = {
585     {gl::DrawElementsType::UnsignedByte, VK_INDEX_TYPE_UINT16},
586     {gl::DrawElementsType::UnsignedShort, VK_INDEX_TYPE_UINT16},
587     {gl::DrawElementsType::UnsignedInt, VK_INDEX_TYPE_UINT32},
588 };
589 
590 constexpr gl::ShaderMap<VkShaderStageFlagBits> kShaderStageMap = {
591     {gl::ShaderType::Vertex, VK_SHADER_STAGE_VERTEX_BIT},
592     {gl::ShaderType::Fragment, VK_SHADER_STAGE_FRAGMENT_BIT},
593     {gl::ShaderType::Geometry, VK_SHADER_STAGE_GEOMETRY_BIT},
594     {gl::ShaderType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
595 };
596 
597 void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
598 void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
599 VkImageType GetImageType(gl::TextureType textureType);
600 VkImageViewType GetImageViewType(gl::TextureType textureType);
601 VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
602 VkShaderStageFlags GetShaderStageFlags(gl::ShaderBitSet activeShaders);
603 
604 void GetViewport(const gl::Rectangle &viewport,
605                  float nearPlane,
606                  float farPlane,
607                  bool invertViewport,
608                  GLint renderAreaHeight,
609                  VkViewport *viewportOut);
610 
611 void GetExtentsAndLayerCount(gl::TextureType textureType,
612                              const gl::Extents &extents,
613                              VkExtent3D *extentsOut,
614                              uint32_t *layerCountOut);
615 }  // namespace gl_vk
616 
617 namespace vk_gl
618 {
619 // Find set bits in sampleCounts and add the corresponding sample count to the set.
620 void AddSampleCounts(VkSampleCountFlags sampleCounts, gl::SupportedSampleSet *outSet);
621 // Return the maximum sample count with a bit set in |sampleCounts|.
622 GLuint GetMaxSampleCount(VkSampleCountFlags sampleCounts);
623 // Return a supported sample count that's at least as large as the requested one.
624 GLuint GetSampleCount(VkSampleCountFlags supportedCounts, GLuint requestedCount);
625 }  // namespace vk_gl
626 
627 }  // namespace rx
628 
629 #define ANGLE_VK_TRY(context, command)                                                 \
630     do                                                                                 \
631     {                                                                                  \
632         auto ANGLE_LOCAL_VAR = command;                                                \
633         if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR != VK_SUCCESS))                             \
634         {                                                                              \
635             context->handleError(ANGLE_LOCAL_VAR, __FILE__, ANGLE_FUNCTION, __LINE__); \
636             return angle::Result::Stop;                                                \
637         }                                                                              \
638     } while (0)
639 
640 #define ANGLE_VK_CHECK(context, test, error) ANGLE_VK_TRY(context, test ? VK_SUCCESS : error)
641 
642 #define ANGLE_VK_CHECK_MATH(context, result) \
643     ANGLE_VK_CHECK(context, result, VK_ERROR_VALIDATION_FAILED_EXT)
644 
645 #define ANGLE_VK_CHECK_ALLOC(context, result) \
646     ANGLE_VK_CHECK(context, result, VK_ERROR_OUT_OF_HOST_MEMORY)
647 
648 #define ANGLE_VK_UNREACHABLE(context) \
649     UNREACHABLE();                    \
650     ANGLE_VK_CHECK(context, false, VK_ERROR_FEATURE_NOT_PRESENT)
651 
652 #endif  // LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
653