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