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