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 // RendererVk.h:
7 //    Defines the class interface for RendererVk.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
11 #define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
12 
13 #include <deque>
14 #include <memory>
15 #include <mutex>
16 
17 #include "vk_ext_provoking_vertex.h"
18 #include "volk.h"
19 
20 #include "common/PackedEnums.h"
21 #include "common/PoolAlloc.h"
22 #include "common/angleutils.h"
23 #include "libANGLE/BlobCache.h"
24 #include "libANGLE/Caps.h"
25 #include "libANGLE/renderer/vulkan/QueryVk.h"
26 #include "libANGLE/renderer/vulkan/ResourceVk.h"
27 #include "libANGLE/renderer/vulkan/UtilsVk.h"
28 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
29 #include "libANGLE/renderer/vulkan/vk_helpers.h"
30 #include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
31 
32 namespace egl
33 {
34 class Display;
35 class BlobCache;
36 }  // namespace egl
37 
38 namespace rx
39 {
40 class DisplayVk;
41 class FramebufferVk;
42 
43 namespace vk
44 {
45 struct Format;
46 }  // namespace vk
47 
48 // Supports one semaphore from current surface, and one semaphore passed to
49 // glSignalSemaphoreEXT.
50 using SignalSemaphoreVector = angle::FixedVector<VkSemaphore, 2>;
51 
CollectGarbage(std::vector<vk::GarbageObject> * garbageOut)52 inline void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut) {}
53 
54 template <typename ArgT, typename... ArgsT>
CollectGarbage(std::vector<vk::GarbageObject> * garbageOut,ArgT object,ArgsT...objectsIn)55 void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut, ArgT object, ArgsT... objectsIn)
56 {
57     if (object->valid())
58     {
59         garbageOut->emplace_back(vk::GarbageObject::Get(object));
60     }
61     CollectGarbage(garbageOut, objectsIn...);
62 }
63 
64 class RendererVk : angle::NonCopyable
65 {
66   public:
67     RendererVk();
68     ~RendererVk();
69 
70     angle::Result initialize(DisplayVk *displayVk,
71                              egl::Display *display,
72                              const char *wsiExtension,
73                              const char *wsiLayer);
74     // Reload volk vk* function ptrs if needed for an already initialized RendererVk
75     void reloadVolkIfNeeded() const;
76     void onDestroy();
77 
78     void notifyDeviceLost();
79     bool isDeviceLost() const;
80 
81     std::string getVendorString() const;
82     std::string getRendererDescription() const;
83 
84     gl::Version getMaxSupportedESVersion() const;
85     gl::Version getMaxConformantESVersion() const;
86 
getInstance()87     VkInstance getInstance() const { return mInstance; }
getPhysicalDevice()88     VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; }
getPhysicalDeviceProperties()89     const VkPhysicalDeviceProperties &getPhysicalDeviceProperties() const
90     {
91         return mPhysicalDeviceProperties;
92     }
getPhysicalDeviceSubgroupProperties()93     const VkPhysicalDeviceSubgroupProperties &getPhysicalDeviceSubgroupProperties() const
94     {
95         return mPhysicalDeviceSubgroupProperties;
96     }
getPhysicalDeviceFeatures()97     const VkPhysicalDeviceFeatures &getPhysicalDeviceFeatures() const
98     {
99         return mPhysicalDeviceFeatures;
100     }
getDevice()101     VkDevice getDevice() const { return mDevice; }
102 
103     angle::Result selectPresentQueueForSurface(DisplayVk *displayVk,
104                                                VkSurfaceKHR surface,
105                                                uint32_t *presentQueueOut);
106 
107     const gl::Caps &getNativeCaps() const;
108     const gl::TextureCapsMap &getNativeTextureCaps() const;
109     const gl::Extensions &getNativeExtensions() const;
110     const gl::Limitations &getNativeLimitations() const;
111 
getQueueFamilyIndex()112     uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
getQueueFamilyProperties()113     const VkQueueFamilyProperties &getQueueFamilyProperties() const
114     {
115         return mQueueFamilyProperties[mCurrentQueueFamilyIndex];
116     }
117 
getMemoryProperties()118     const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; }
119 
120     // TODO(jmadill): We could pass angle::FormatID here.
getFormat(GLenum internalFormat)121     const vk::Format &getFormat(GLenum internalFormat) const
122     {
123         return mFormatTable[internalFormat];
124     }
125 
getFormat(angle::FormatID formatID)126     const vk::Format &getFormat(angle::FormatID formatID) const { return mFormatTable[formatID]; }
127 
128     // Queries the descriptor set layout cache. Creates the layout if not present.
129     angle::Result getDescriptorSetLayout(
130         vk::Context *context,
131         const vk::DescriptorSetLayoutDesc &desc,
132         vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
133 
134     // Queries the pipeline layout cache. Creates the layout if not present.
135     angle::Result getPipelineLayout(vk::Context *context,
136                                     const vk::PipelineLayoutDesc &desc,
137                                     const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
138                                     vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
139 
140     angle::Result getPipelineCacheSize(DisplayVk *displayVk, size_t *pipelineCacheSizeOut);
141     angle::Result syncPipelineCacheVk(DisplayVk *displayVk);
142 
143     // Issues a new serial for linked shader modules. Used in the pipeline cache.
144     Serial issueShaderSerial();
145 
getFeatures()146     const angle::FeaturesVk &getFeatures() const { return mFeatures; }
getMaxVertexAttribDivisor()147     uint32_t getMaxVertexAttribDivisor() const { return mMaxVertexAttribDivisor; }
getMaxVertexAttribStride()148     VkDeviceSize getMaxVertexAttribStride() const { return mMaxVertexAttribStride; }
149 
getMinImportedHostPointerAlignment()150     VkDeviceSize getMinImportedHostPointerAlignment() const
151     {
152         return mMinImportedHostPointerAlignment;
153     }
154 
isMockICDEnabled()155     bool isMockICDEnabled() const { return mEnabledICD == vk::ICD::Mock; }
156 
157     // Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and
158     // bufferFeatures).  Looks through mandatory features first, and falls back to querying the
159     // device (first time only).
160     bool hasLinearImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
161     VkFormatFeatureFlags getImageFormatFeatureBits(VkFormat format,
162                                                    const VkFormatFeatureFlags featureBits);
163     bool hasImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
164     bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
165 
getDriverPriority(egl::ContextPriority priority)166     ANGLE_INLINE egl::ContextPriority getDriverPriority(egl::ContextPriority priority)
167     {
168         return mPriorities[priority];
169     }
170 
171     angle::Result queueSubmit(vk::Context *context,
172                               egl::ContextPriority priority,
173                               const VkSubmitInfo &submitInfo,
174                               const vk::Fence *fence,
175                               Serial *serialOut);
176     angle::Result queueWaitIdle(vk::Context *context, egl::ContextPriority priority);
177     angle::Result deviceWaitIdle(vk::Context *context);
178     VkResult queuePresent(egl::ContextPriority priority, const VkPresentInfoKHR &presentInfo);
179 
180     // This command buffer should be submitted immediately via queueSubmitOneOff.
181     angle::Result getCommandBufferOneOff(vk::Context *context,
182                                          vk::PrimaryCommandBuffer *commandBufferOut);
183 
184     // Fire off a single command buffer immediately with default priority.
185     // Command buffer must be allocated with getCommandBufferOneOff and is reclaimed.
186     angle::Result queueSubmitOneOff(vk::Context *context,
187                                     vk::PrimaryCommandBuffer &&primary,
188                                     egl::ContextPriority priority,
189                                     Serial *serialOut);
190 
191     angle::Result newSharedFence(vk::Context *context, vk::Shared<vk::Fence> *sharedFenceOut);
resetSharedFence(vk::Shared<vk::Fence> * sharedFenceIn)192     inline void resetSharedFence(vk::Shared<vk::Fence> *sharedFenceIn)
193     {
194         sharedFenceIn->resetAndRecycle(&mFenceRecycler);
195     }
196 
197     template <typename... ArgsT>
collectGarbageAndReinit(vk::SharedResourceUse * use,ArgsT...garbageIn)198     void collectGarbageAndReinit(vk::SharedResourceUse *use, ArgsT... garbageIn)
199     {
200         std::vector<vk::GarbageObject> sharedGarbage;
201         CollectGarbage(&sharedGarbage, garbageIn...);
202         if (!sharedGarbage.empty())
203         {
204             collectGarbage(std::move(*use), std::move(sharedGarbage));
205         }
206         else
207         {
208             // Force releasing "use" even if no garbage was created.
209             use->release();
210         }
211         // Keep "use" valid.
212         use->init();
213     }
214 
collectGarbage(vk::SharedResourceUse && use,std::vector<vk::GarbageObject> && sharedGarbage)215     void collectGarbage(vk::SharedResourceUse &&use, std::vector<vk::GarbageObject> &&sharedGarbage)
216     {
217         if (!sharedGarbage.empty())
218         {
219             mSharedGarbage.emplace_back(std::move(use), std::move(sharedGarbage));
220         }
221     }
222 
223     static constexpr size_t kMaxExtensionNames = 200;
224     using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>;
225 
226     angle::Result getPipelineCache(vk::PipelineCache **pipelineCache);
onNewGraphicsPipeline()227     void onNewGraphicsPipeline() { mPipelineCacheDirty = true; }
228 
229     void onNewValidationMessage(const std::string &message);
230     std::string getAndClearLastValidationMessage(uint32_t *countSinceLastClear);
231 
232     uint64_t getMaxFenceWaitTimeNs() const;
getCurrentQueueSerial()233     Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
getLastSubmittedQueueSerial()234     Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; }
getLastCompletedQueueSerial()235     Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; }
236 
237     void onCompletedSerial(Serial serial);
238 
shouldCleanupGarbage()239     bool shouldCleanupGarbage()
240     {
241         return (mSharedGarbage.size() > mGarbageCollectionFlushThreshold);
242     }
243 
enableDebugUtils()244     bool enableDebugUtils() const { return mEnableDebugUtils; }
245 
246   private:
247     angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
248     void ensureCapsInitialized() const;
249 
250     void queryDeviceExtensionFeatures(const ExtensionNameList &deviceExtensionNames);
251 
252     void initFeatures(DisplayVk *display, const ExtensionNameList &extensions);
253     void initPipelineCacheVkKey();
254     angle::Result initPipelineCache(DisplayVk *display,
255                                     vk::PipelineCache *pipelineCache,
256                                     bool *success);
257 
258     template <VkFormatFeatureFlags VkFormatProperties::*features>
259     VkFormatFeatureFlags getFormatFeatureBits(VkFormat format,
260                                               const VkFormatFeatureFlags featureBits);
261 
262     template <VkFormatFeatureFlags VkFormatProperties::*features>
263     bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
264 
265     angle::Result cleanupGarbage(bool block);
266 
267     egl::Display *mDisplay;
268 
269     mutable bool mCapsInitialized;
270     mutable gl::Caps mNativeCaps;
271     mutable gl::TextureCapsMap mNativeTextureCaps;
272     mutable gl::Extensions mNativeExtensions;
273     mutable gl::Limitations mNativeLimitations;
274     mutable angle::FeaturesVk mFeatures;
275 
276     VkInstance mInstance;
277     bool mEnableValidationLayers;
278     bool mEnableDebugUtils;
279     vk::ICD mEnabledICD;
280     VkDebugUtilsMessengerEXT mDebugUtilsMessenger;
281     VkDebugReportCallbackEXT mDebugReportCallback;
282     VkPhysicalDevice mPhysicalDevice;
283     VkPhysicalDeviceProperties mPhysicalDeviceProperties;
284     VkPhysicalDeviceFeatures mPhysicalDeviceFeatures;
285     VkPhysicalDeviceLineRasterizationFeaturesEXT mLineRasterizationFeatures;
286     VkPhysicalDeviceProvokingVertexFeaturesEXT mProvokingVertexFeatures;
287     VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT mVertexAttributeDivisorFeatures;
288     VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT mVertexAttributeDivisorProperties;
289     VkPhysicalDeviceTransformFeedbackFeaturesEXT mTransformFeedbackFeatures;
290     VkPhysicalDeviceIndexTypeUint8FeaturesEXT mIndexTypeUint8Features;
291     VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties;
292     VkPhysicalDeviceExternalMemoryHostPropertiesEXT mPhysicalDeviceExternalMemoryHostProperties;
293     std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
294     std::mutex mQueueMutex;
295     angle::PackedEnumMap<egl::ContextPriority, VkQueue> mQueues;
296     angle::PackedEnumMap<egl::ContextPriority, egl::ContextPriority> mPriorities;
297     uint32_t mCurrentQueueFamilyIndex;
298     uint32_t mMaxVertexAttribDivisor;
299     VkDeviceSize mMaxVertexAttribStride;
300     VkDeviceSize mMinImportedHostPointerAlignment;
301     VkDevice mDevice;
302     AtomicSerialFactory mQueueSerialFactory;
303     AtomicSerialFactory mShaderSerialFactory;
304 
305     Serial mLastCompletedQueueSerial;
306     Serial mLastSubmittedQueueSerial;
307     Serial mCurrentQueueSerial;
308 
309     bool mDeviceLost;
310 
311     vk::Recycler<vk::Fence> mFenceRecycler;
312 
313     std::mutex mGarbageMutex;
314     vk::SharedGarbageList mSharedGarbage;
315 
316     vk::MemoryProperties mMemoryProperties;
317     vk::FormatTable mFormatTable;
318 
319     // All access to the pipeline cache is done through EGL objects so it is thread safe to not use
320     // a lock.
321     vk::PipelineCache mPipelineCache;
322     egl::BlobCache::Key mPipelineCacheVkBlobKey;
323     uint32_t mPipelineCacheVkUpdateTimeout;
324     bool mPipelineCacheDirty;
325     bool mPipelineCacheInitialized;
326 
327     // A cache of VkFormatProperties as queried from the device over time.
328     std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties;
329 
330     // ANGLE uses a PipelineLayout cache to store compatible pipeline layouts.
331     std::mutex mPipelineLayoutCacheMutex;
332     PipelineLayoutCache mPipelineLayoutCache;
333 
334     // DescriptorSetLayouts are also managed in a cache.
335     std::mutex mDescriptorSetLayoutCacheMutex;
336     DescriptorSetLayoutCache mDescriptorSetLayoutCache;
337 
338     // Latest validation data for debug overlay.
339     std::string mLastValidationMessage;
340     uint32_t mValidationMessageCount;
341 
342     // How close to VkPhysicalDeviceLimits::maxMemoryAllocationCount we allow ourselves to get
343     static constexpr double kPercentMaxMemoryAllocationCount = 0.3;
344     // How many objects to garbage collect before issuing a flush()
345     uint32_t mGarbageCollectionFlushThreshold;
346 
347     // Only used for "one off" command buffers.
348     vk::CommandPool mOneOffCommandPool;
349 
350     struct PendingOneOffCommands
351     {
352         Serial serial;
353         vk::PrimaryCommandBuffer commandBuffer;
354     };
355     std::deque<PendingOneOffCommands> mPendingOneOffCommands;
356 
357     // track whether we initialized (or released) glslang
358     bool mGlslangInitialized;
359 };
360 
361 }  // namespace rx
362 
363 #endif  // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
364