|  | // | 
|  | // Copyright 2016 The ANGLE Project Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  | // | 
|  | // RendererVk.h: | 
|  | //    Defines the class interface for RendererVk. | 
|  | // | 
|  |  | 
|  | #ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ | 
|  | #define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ | 
|  |  | 
|  | #include <vulkan/vulkan.h> | 
|  | #include <memory> | 
|  | #include <mutex> | 
|  | #include "vk_ext_provoking_vertex.h" | 
|  |  | 
|  | #include "common/PoolAlloc.h" | 
|  | #include "common/angleutils.h" | 
|  | #include "libANGLE/BlobCache.h" | 
|  | #include "libANGLE/Caps.h" | 
|  | #include "libANGLE/renderer/vulkan/CommandGraph.h" | 
|  | #include "libANGLE/renderer/vulkan/QueryVk.h" | 
|  | #include "libANGLE/renderer/vulkan/UtilsVk.h" | 
|  | #include "libANGLE/renderer/vulkan/vk_format_utils.h" | 
|  | #include "libANGLE/renderer/vulkan/vk_helpers.h" | 
|  | #include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h" | 
|  |  | 
|  | namespace egl | 
|  | { | 
|  | class Display; | 
|  | class BlobCache; | 
|  | }  // namespace egl | 
|  |  | 
|  | namespace rx | 
|  | { | 
|  | class DisplayVk; | 
|  | class FramebufferVk; | 
|  |  | 
|  | namespace vk | 
|  | { | 
|  | struct Format; | 
|  | }  // namespace vk | 
|  |  | 
|  | // Supports one semaphore from current surface, and one semaphore passed to | 
|  | // glSignalSemaphoreEXT. | 
|  | using SignalSemaphoreVector = angle::FixedVector<VkSemaphore, 2>; | 
|  |  | 
|  | inline void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut) {} | 
|  |  | 
|  | template <typename ArgT, typename... ArgsT> | 
|  | void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut, ArgT object, ArgsT... objectsIn) | 
|  | { | 
|  | if (object->valid()) | 
|  | { | 
|  | garbageOut->emplace_back(vk::GarbageObject::Get(object)); | 
|  | } | 
|  | CollectGarbage(garbageOut, objectsIn...); | 
|  | } | 
|  |  | 
|  | class RendererVk : angle::NonCopyable | 
|  | { | 
|  | public: | 
|  | RendererVk(); | 
|  | ~RendererVk(); | 
|  |  | 
|  | angle::Result initialize(DisplayVk *displayVk, | 
|  | egl::Display *display, | 
|  | const char *wsiExtension, | 
|  | const char *wsiLayer); | 
|  | void onDestroy(vk::Context *context); | 
|  |  | 
|  | void notifyDeviceLost(); | 
|  | bool isDeviceLost() const; | 
|  |  | 
|  | std::string getVendorString() const; | 
|  | std::string getRendererDescription() const; | 
|  |  | 
|  | gl::Version getMaxSupportedESVersion() const; | 
|  | gl::Version getMaxConformantESVersion() const; | 
|  |  | 
|  | VkInstance getInstance() const { return mInstance; } | 
|  | VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; } | 
|  | const VkPhysicalDeviceProperties &getPhysicalDeviceProperties() const | 
|  | { | 
|  | return mPhysicalDeviceProperties; | 
|  | } | 
|  | const VkPhysicalDeviceSubgroupProperties &getPhysicalDeviceSubgroupProperties() const | 
|  | { | 
|  | return mPhysicalDeviceSubgroupProperties; | 
|  | } | 
|  | const VkPhysicalDeviceFeatures &getPhysicalDeviceFeatures() const | 
|  | { | 
|  | return mPhysicalDeviceFeatures; | 
|  | } | 
|  | VkDevice getDevice() const { return mDevice; } | 
|  |  | 
|  | angle::Result selectPresentQueueForSurface(DisplayVk *displayVk, | 
|  | VkSurfaceKHR surface, | 
|  | uint32_t *presentQueueOut); | 
|  |  | 
|  | const gl::Caps &getNativeCaps() const; | 
|  | const gl::TextureCapsMap &getNativeTextureCaps() const; | 
|  | const gl::Extensions &getNativeExtensions() const; | 
|  | const gl::Limitations &getNativeLimitations() const; | 
|  |  | 
|  | uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; } | 
|  |  | 
|  | const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; } | 
|  |  | 
|  | // TODO(jmadill): We could pass angle::FormatID here. | 
|  | const vk::Format &getFormat(GLenum internalFormat) const | 
|  | { | 
|  | return mFormatTable[internalFormat]; | 
|  | } | 
|  |  | 
|  | const vk::Format &getFormat(angle::FormatID formatID) const { return mFormatTable[formatID]; } | 
|  |  | 
|  | // Queries the descriptor set layout cache. Creates the layout if not present. | 
|  | angle::Result getDescriptorSetLayout( | 
|  | vk::Context *context, | 
|  | const vk::DescriptorSetLayoutDesc &desc, | 
|  | vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut); | 
|  |  | 
|  | // Queries the pipeline layout cache. Creates the layout if not present. | 
|  | angle::Result getPipelineLayout(vk::Context *context, | 
|  | const vk::PipelineLayoutDesc &desc, | 
|  | const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts, | 
|  | vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut); | 
|  |  | 
|  | angle::Result getPipelineCacheSize(DisplayVk *displayVk, size_t *pipelineCacheSizeOut); | 
|  | angle::Result syncPipelineCacheVk(DisplayVk *displayVk); | 
|  |  | 
|  | // Issues a new serial for linked shader modules. Used in the pipeline cache. | 
|  | Serial issueShaderSerial(); | 
|  |  | 
|  | const angle::FeaturesVk &getFeatures() const | 
|  | { | 
|  | ASSERT(mFeaturesInitialized); | 
|  | return mFeatures; | 
|  | } | 
|  | uint32_t getMaxVertexAttribDivisor() const { return mMaxVertexAttribDivisor; } | 
|  |  | 
|  | bool isMockICDEnabled() const { return mEnabledICD == vk::ICD::Mock; } | 
|  |  | 
|  | // Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and | 
|  | // bufferFeatures).  Looks through mandatory features first, and falls back to querying the | 
|  | // device (first time only). | 
|  | bool hasLinearImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); | 
|  | VkFormatFeatureFlags getImageFormatFeatureBits(VkFormat format, | 
|  | const VkFormatFeatureFlags featureBits); | 
|  | bool hasImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); | 
|  | bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); | 
|  |  | 
|  | angle::Result queueSubmit(vk::Context *context, | 
|  | const VkSubmitInfo &submitInfo, | 
|  | const vk::Fence &fence, | 
|  | Serial *serialOut); | 
|  | angle::Result queueWaitIdle(vk::Context *context); | 
|  | VkResult queuePresent(const VkPresentInfoKHR &presentInfo); | 
|  |  | 
|  | angle::Result newSharedFence(vk::Context *context, vk::Shared<vk::Fence> *sharedFenceOut); | 
|  | inline void resetSharedFence(vk::Shared<vk::Fence> *sharedFenceIn) | 
|  | { | 
|  | sharedFenceIn->resetAndRecycle(&mFenceRecycler); | 
|  | } | 
|  |  | 
|  | template <typename... ArgsT> | 
|  | void collectGarbageAndReinit(vk::SharedResourceUse *use, ArgsT... garbageIn) | 
|  | { | 
|  | std::vector<vk::GarbageObject> sharedGarbage; | 
|  | CollectGarbage(&sharedGarbage, garbageIn...); | 
|  | if (!sharedGarbage.empty()) | 
|  | { | 
|  | collectGarbage(std::move(*use), std::move(sharedGarbage)); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Force releasing "use" even if no garbage was created. | 
|  | use->release(); | 
|  | } | 
|  | // Keep "use" valid. | 
|  | use->init(); | 
|  | } | 
|  |  | 
|  | void collectGarbage(vk::SharedResourceUse &&use, std::vector<vk::GarbageObject> &&sharedGarbage) | 
|  | { | 
|  | mSharedGarbage.emplace_back(std::move(use), std::move(sharedGarbage)); | 
|  | } | 
|  |  | 
|  | static constexpr size_t kMaxExtensionNames = 200; | 
|  | using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>; | 
|  |  | 
|  | angle::Result getPipelineCache(vk::PipelineCache **pipelineCache); | 
|  | void onNewGraphicsPipeline() { mPipelineCacheDirty = true; } | 
|  |  | 
|  | void onNewValidationMessage(const std::string &message); | 
|  | std::string getAndClearLastValidationMessage(uint32_t *countSinceLastClear); | 
|  |  | 
|  | uint64_t getMaxFenceWaitTimeNs() const; | 
|  | Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; } | 
|  | Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; } | 
|  | Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; } | 
|  |  | 
|  | void onCompletedSerial(Serial serial); | 
|  |  | 
|  | bool shouldCleanupGarbage() | 
|  | { | 
|  | return (mSharedGarbage.size() > mGarbageCollectionFlushThreshold); | 
|  | } | 
|  |  | 
|  | private: | 
|  | angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex); | 
|  | void ensureCapsInitialized() const; | 
|  |  | 
|  | void initFeatures(const ExtensionNameList &extensions); | 
|  | void initPipelineCacheVkKey(); | 
|  | angle::Result initPipelineCache(DisplayVk *display, | 
|  | vk::PipelineCache *pipelineCache, | 
|  | bool *success); | 
|  |  | 
|  | template <VkFormatFeatureFlags VkFormatProperties::*features> | 
|  | VkFormatFeatureFlags getFormatFeatureBits(VkFormat format, | 
|  | const VkFormatFeatureFlags featureBits); | 
|  |  | 
|  | template <VkFormatFeatureFlags VkFormatProperties::*features> | 
|  | bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); | 
|  |  | 
|  | angle::Result cleanupGarbage(vk::Context *context, bool block); | 
|  |  | 
|  | egl::Display *mDisplay; | 
|  |  | 
|  | mutable bool mCapsInitialized; | 
|  | mutable gl::Caps mNativeCaps; | 
|  | mutable gl::TextureCapsMap mNativeTextureCaps; | 
|  | mutable gl::Extensions mNativeExtensions; | 
|  | mutable gl::Limitations mNativeLimitations; | 
|  | mutable bool mFeaturesInitialized; | 
|  | mutable angle::FeaturesVk mFeatures; | 
|  |  | 
|  | VkInstance mInstance; | 
|  | bool mEnableValidationLayers; | 
|  | vk::ICD mEnabledICD; | 
|  | VkDebugUtilsMessengerEXT mDebugUtilsMessenger; | 
|  | VkDebugReportCallbackEXT mDebugReportCallback; | 
|  | VkPhysicalDevice mPhysicalDevice; | 
|  | VkPhysicalDeviceProperties mPhysicalDeviceProperties; | 
|  | VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties; | 
|  | VkPhysicalDeviceFeatures mPhysicalDeviceFeatures; | 
|  | VkPhysicalDeviceLineRasterizationFeaturesEXT mLineRasterizationFeatures; | 
|  | VkPhysicalDeviceProvokingVertexFeaturesEXT mProvokingVertexFeatures; | 
|  | std::vector<VkQueueFamilyProperties> mQueueFamilyProperties; | 
|  | std::mutex mQueueMutex; | 
|  | VkQueue mQueue; | 
|  | uint32_t mCurrentQueueFamilyIndex; | 
|  | uint32_t mMaxVertexAttribDivisor; | 
|  | VkDevice mDevice; | 
|  | AtomicSerialFactory mQueueSerialFactory; | 
|  | AtomicSerialFactory mShaderSerialFactory; | 
|  |  | 
|  | Serial mLastCompletedQueueSerial; | 
|  | Serial mLastSubmittedQueueSerial; | 
|  | Serial mCurrentQueueSerial; | 
|  |  | 
|  | bool mDeviceLost; | 
|  |  | 
|  | vk::Recycler<vk::Fence> mFenceRecycler; | 
|  |  | 
|  | std::mutex mGarbageMutex; | 
|  | vk::SharedGarbageList mSharedGarbage; | 
|  |  | 
|  | vk::MemoryProperties mMemoryProperties; | 
|  | vk::FormatTable mFormatTable; | 
|  |  | 
|  | // All access to the pipeline cache is done through EGL objects so it is thread safe to not use | 
|  | // a lock. | 
|  | vk::PipelineCache mPipelineCache; | 
|  | egl::BlobCache::Key mPipelineCacheVkBlobKey; | 
|  | uint32_t mPipelineCacheVkUpdateTimeout; | 
|  | bool mPipelineCacheDirty; | 
|  | bool mPipelineCacheInitialized; | 
|  |  | 
|  | // A cache of VkFormatProperties as queried from the device over time. | 
|  | std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties; | 
|  |  | 
|  | // ANGLE uses a PipelineLayout cache to store compatible pipeline layouts. | 
|  | std::mutex mPipelineLayoutCacheMutex; | 
|  | PipelineLayoutCache mPipelineLayoutCache; | 
|  |  | 
|  | // DescriptorSetLayouts are also managed in a cache. | 
|  | std::mutex mDescriptorSetLayoutCacheMutex; | 
|  | DescriptorSetLayoutCache mDescriptorSetLayoutCache; | 
|  |  | 
|  | // Latest validation data for debug overlay. | 
|  | std::string mLastValidationMessage; | 
|  | uint32_t mValidationMessageCount; | 
|  |  | 
|  | // How close to VkPhysicalDeviceLimits::maxMemoryAllocationCount we allow ourselves to get | 
|  | static constexpr double kPercentMaxMemoryAllocationCount = 0.3; | 
|  | // How many objects to garbage collect before issuing a flush() | 
|  | uint32_t mGarbageCollectionFlushThreshold; | 
|  | }; | 
|  |  | 
|  | }  // namespace rx | 
|  |  | 
|  | #endif  // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ |