• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/vulkan/BackendVk.h"
16 
17 #include "common/BitSetIterator.h"
18 #include "common/Log.h"
19 #include "common/SystemUtils.h"
20 #include "dawn_native/Instance.h"
21 #include "dawn_native/VulkanBackend.h"
22 #include "dawn_native/vulkan/AdapterVk.h"
23 #include "dawn_native/vulkan/UtilsVulkan.h"
24 #include "dawn_native/vulkan/VulkanError.h"
25 
26 // TODO(crbug.com/dawn/283): Link against the Vulkan Loader and remove this.
27 #if defined(DAWN_ENABLE_SWIFTSHADER)
28 #    if defined(DAWN_PLATFORM_LINUX) || defined(DAWN_PLATFORM_FUSCHIA)
29 constexpr char kSwiftshaderLibName[] = "libvk_swiftshader.so";
30 #    elif defined(DAWN_PLATFORM_WINDOWS)
31 constexpr char kSwiftshaderLibName[] = "vk_swiftshader.dll";
32 #    elif defined(DAWN_PLATFORM_MACOS)
33 constexpr char kSwiftshaderLibName[] = "libvk_swiftshader.dylib";
34 #    else
35 #        error "Unimplemented Swiftshader Vulkan backend platform"
36 #    endif
37 #endif
38 
39 #if defined(DAWN_PLATFORM_LINUX)
40 #    if defined(DAWN_PLATFORM_ANDROID)
41 constexpr char kVulkanLibName[] = "libvulkan.so";
42 #    else
43 constexpr char kVulkanLibName[] = "libvulkan.so.1";
44 #    endif
45 #elif defined(DAWN_PLATFORM_WINDOWS)
46 constexpr char kVulkanLibName[] = "vulkan-1.dll";
47 #elif defined(DAWN_PLATFORM_MACOS)
48 constexpr char kVulkanLibName[] = "libvulkan.dylib";
49 #elif defined(DAWN_PLATFORM_FUCHSIA)
50 constexpr char kVulkanLibName[] = "libvulkan.so";
51 #else
52 #    error "Unimplemented Vulkan backend platform"
53 #endif
54 
55 struct SkippedMessage {
56     const char* messageId;
57     const char* messageContents;
58 };
59 
60 // Array of Validation error/warning messages that will be ignored, should include bugID
61 constexpr SkippedMessage kSkippedMessages[] = {
62     // These errors are generated when simultaneously using a read-only depth/stencil attachment as
63     // a texture binding. This is valid Vulkan.
64     //
65     // When storeOp=NONE is not present, Dawn uses storeOp=STORE, but Vulkan validation layer
66     // considers the image read-only and produces a hazard. Dawn can't rely on storeOp=NONE and
67     // so this is not expected to be worked around.
68     // See http://crbug.com/dawn/1225 for more details.
69     {"SYNC-HAZARD-WRITE_AFTER_READ",
70      "depth aspect during store with storeOp VK_ATTACHMENT_STORE_OP_STORE. Access info (usage: "
71      "SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: "
72      "SYNC_FRAGMENT_SHADER_SHADER_STORAGE_READ, read_barriers: VK_PIPELINE_STAGE_2_NONE_KHR, "},
73 
74     {"SYNC-HAZARD-WRITE_AFTER_READ",
75      "stencil aspect during store with stencilStoreOp VK_ATTACHMENT_STORE_OP_STORE. Access info "
76      "(usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: "
77      "SYNC_FRAGMENT_SHADER_SHADER_STORAGE_READ, read_barriers: VK_PIPELINE_STAGE_2_NONE_KHR, "},
78 };
79 
80 namespace dawn_native { namespace vulkan {
81 
82     namespace {
83 
84         static constexpr ICD kICDs[] = {
85             ICD::None,
86 #if defined(DAWN_ENABLE_SWIFTSHADER)
87             ICD::SwiftShader,
88 #endif  // defined(DAWN_ENABLE_SWIFTSHADER)
89         };
90 
91         // Suppress validation errors that are known. Returns false in that case.
ShouldReportDebugMessage(const char * messageId,const char * message)92         bool ShouldReportDebugMessage(const char* messageId, const char* message) {
93             for (const SkippedMessage& msg : kSkippedMessages) {
94                 if (strstr(messageId, msg.messageId) != nullptr &&
95                     strstr(message, msg.messageContents) != nullptr) {
96                     return false;
97                 }
98             }
99             return true;
100         }
101 
102         VKAPI_ATTR VkBool32 VKAPI_CALL
OnDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,VkDebugUtilsMessageTypeFlagsEXT,const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData,void *)103         OnDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
104                              VkDebugUtilsMessageTypeFlagsEXT /* messageTypes */,
105                              const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
106                              void* /* pUserData */) {
107             if (ShouldReportDebugMessage(pCallbackData->pMessageIdName, pCallbackData->pMessage)) {
108                 dawn::WarningLog() << pCallbackData->pMessage;
109                 ASSERT((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) == 0);
110             }
111             return VK_FALSE;
112         }
113 
114         // A debug callback specifically for instance creation so that we don't fire an ASSERT when
115         // the instance fails creation in an expected manner (for example the system not having
116         // Vulkan drivers).
OnInstanceCreationDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,VkDebugUtilsMessageTypeFlagsEXT,const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData,void *)117         VKAPI_ATTR VkBool32 VKAPI_CALL OnInstanceCreationDebugUtilsCallback(
118             VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
119             VkDebugUtilsMessageTypeFlagsEXT /* messageTypes */,
120             const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
121             void* /* pUserData */) {
122             dawn::WarningLog() << pCallbackData->pMessage;
123             return VK_FALSE;
124         }
125 
126     }  // anonymous namespace
127 
128     VulkanInstance::VulkanInstance() = default;
129 
~VulkanInstance()130     VulkanInstance::~VulkanInstance() {
131         if (mDebugUtilsMessenger != VK_NULL_HANDLE) {
132             mFunctions.DestroyDebugUtilsMessengerEXT(mInstance, mDebugUtilsMessenger, nullptr);
133             mDebugUtilsMessenger = VK_NULL_HANDLE;
134         }
135 
136         // VkPhysicalDevices are destroyed when the VkInstance is destroyed
137         if (mInstance != VK_NULL_HANDLE) {
138             mFunctions.DestroyInstance(mInstance, nullptr);
139             mInstance = VK_NULL_HANDLE;
140         }
141     }
142 
GetFunctions() const143     const VulkanFunctions& VulkanInstance::GetFunctions() const {
144         return mFunctions;
145     }
146 
GetVkInstance() const147     VkInstance VulkanInstance::GetVkInstance() const {
148         return mInstance;
149     }
150 
GetGlobalInfo() const151     const VulkanGlobalInfo& VulkanInstance::GetGlobalInfo() const {
152         return mGlobalInfo;
153     }
154 
GetPhysicalDevices() const155     const std::vector<VkPhysicalDevice>& VulkanInstance::GetPhysicalDevices() const {
156         return mPhysicalDevices;
157     }
158 
159     // static
Create(const InstanceBase * instance,ICD icd)160     ResultOrError<Ref<VulkanInstance>> VulkanInstance::Create(const InstanceBase* instance,
161                                                               ICD icd) {
162         Ref<VulkanInstance> vulkanInstance = AcquireRef(new VulkanInstance());
163         DAWN_TRY(vulkanInstance->Initialize(instance, icd));
164         return std::move(vulkanInstance);
165     }
166 
Initialize(const InstanceBase * instance,ICD icd)167     MaybeError VulkanInstance::Initialize(const InstanceBase* instance, ICD icd) {
168         // These environment variables need only be set while loading procs and gathering device
169         // info.
170         ScopedEnvironmentVar vkICDFilenames;
171         ScopedEnvironmentVar vkLayerPath;
172 
173 #if defined(DAWN_ENABLE_VULKAN_LOADER)
174         // If enabled, we use our own built Vulkan loader by specifying an absolute path to the
175         // shared library. Note that when we are currently getting the absolute path for the custom
176         // loader by getting the path to the dawn native library and traversing relative from there.
177         // This has implications for dawn tests because some of them are linking statically to
178         // dawn_native which means the "module" is actually the test as well. If the directory
179         // location of the tests change w.r.t the shared lib then this may break. Essentially we are
180         // assuming that our custom built Vulkan loader will always be in the same directory as the
181         // shared dawn native library and all test binaries that link statically.
182         const std::string resolvedVulkanLibPath = GetModuleDirectory() + kVulkanLibName;
183 #else
184         const std::string resolvedVulkanLibPath = kVulkanLibName;
185 #endif  // defined(DAWN_ENABLE_VULKAN_LOADER)
186 
187         switch (icd) {
188             case ICD::None: {
189                 if (!mVulkanLib.Open(resolvedVulkanLibPath)) {
190                     return DAWN_FORMAT_INTERNAL_ERROR("Couldn't load %s.", resolvedVulkanLibPath);
191                 }
192                 break;
193             }
194             case ICD::SwiftShader: {
195 #if defined(DAWN_ENABLE_SWIFTSHADER)
196                 // First try to load the system Vulkan driver, if that fails, try to load with
197                 // Swiftshader. Note: The system driver could potentially be Swiftshader if it was
198                 // installed.
199 #    if defined(DAWN_SWIFTSHADER_VK_ICD_JSON)
200                 if (mVulkanLib.Open(resolvedVulkanLibPath)) {
201                     std::string fullSwiftshaderICDPath =
202                         GetExecutableDirectory() + DAWN_SWIFTSHADER_VK_ICD_JSON;
203                     if (!vkICDFilenames.Set("VK_ICD_FILENAMES", fullSwiftshaderICDPath.c_str())) {
204                         return DAWN_FORMAT_INTERNAL_ERROR("Couldn't set VK_ICD_FILENAMES to %s.",
205                                                           fullSwiftshaderICDPath);
206                     }
207                     // Succesfully loaded driver and set VK_ICD_FILENAMES.
208                     break;
209                 } else
210 #    endif  // defined(DAWN_SWIFTSHADER_VK_ICD_JSON)
211             // Fallback to loading SwiftShader directly.
212                     if (mVulkanLib.Open(kSwiftshaderLibName)) {
213                     // Succesfully loaded SwiftShader.
214                     break;
215                 }
216                 return DAWN_FORMAT_INTERNAL_ERROR(
217                     "Failed to load SwiftShader. DAWN_SWIFTSHADER_VK_ICD_JSON was not defined and "
218                     "could not load %s.",
219                     kSwiftshaderLibName);
220 #endif  // defined(DAWN_ENABLE_SWIFTSHADER)
221 
222                 // ICD::SwiftShader should not be passed if SwiftShader is not enabled.
223                 UNREACHABLE();
224             }
225         }
226 
227         if (instance->IsBackendValidationEnabled()) {
228 #if defined(DAWN_ENABLE_VULKAN_VALIDATION_LAYERS)
229             std::string vkDataDir = GetExecutableDirectory() + DAWN_VK_DATA_DIR;
230             if (!vkLayerPath.Set("VK_LAYER_PATH", vkDataDir.c_str())) {
231                 return DAWN_INTERNAL_ERROR("Couldn't set VK_LAYER_PATH");
232             }
233 #else
234             dawn::WarningLog() << "Backend validation enabled but Dawn was not built with "
235                                   "DAWN_ENABLE_VULKAN_VALIDATION_LAYERS.";
236 #endif
237         }
238 
239         DAWN_TRY(mFunctions.LoadGlobalProcs(mVulkanLib));
240 
241         DAWN_TRY_ASSIGN(mGlobalInfo, GatherGlobalInfo(mFunctions));
242 
243         VulkanGlobalKnobs usedGlobalKnobs = {};
244         DAWN_TRY_ASSIGN(usedGlobalKnobs, CreateVkInstance(instance));
245         *static_cast<VulkanGlobalKnobs*>(&mGlobalInfo) = usedGlobalKnobs;
246 
247         DAWN_TRY(mFunctions.LoadInstanceProcs(mInstance, mGlobalInfo));
248 
249         if (usedGlobalKnobs.HasExt(InstanceExt::DebugUtils)) {
250             DAWN_TRY(RegisterDebugUtils());
251         }
252 
253         DAWN_TRY_ASSIGN(mPhysicalDevices, GatherPhysicalDevices(mInstance, mFunctions));
254 
255         return {};
256     }
257 
CreateVkInstance(const InstanceBase * instance)258     ResultOrError<VulkanGlobalKnobs> VulkanInstance::CreateVkInstance(
259         const InstanceBase* instance) {
260         VulkanGlobalKnobs usedKnobs = {};
261         std::vector<const char*> layerNames;
262         InstanceExtSet extensionsToRequest = mGlobalInfo.extensions;
263 
264         auto UseLayerIfAvailable = [&](VulkanLayer layer) {
265             if (mGlobalInfo.layers[layer]) {
266                 layerNames.push_back(GetVulkanLayerInfo(layer).name);
267                 usedKnobs.layers.set(layer, true);
268                 extensionsToRequest |= mGlobalInfo.layerExtensions[layer];
269             }
270         };
271 
272         // vktrace works by instering a layer, but we hide it behind a macro because the vktrace
273         // layer crashes when used without vktrace server started. See this vktrace issue:
274         // https://github.com/LunarG/VulkanTools/issues/254
275         // Also it is good to put it in first position so that it doesn't see Vulkan calls inserted
276         // by other layers.
277 #if defined(DAWN_USE_VKTRACE)
278         UseLayerIfAvailable(VulkanLayer::LunargVkTrace);
279 #endif
280         // RenderDoc installs a layer at the system level for its capture but we don't want to use
281         // it unless we are debugging in RenderDoc so we hide it behind a macro.
282 #if defined(DAWN_USE_RENDERDOC)
283         UseLayerIfAvailable(VulkanLayer::RenderDocCapture);
284 #endif
285 
286         if (instance->IsBackendValidationEnabled()) {
287             UseLayerIfAvailable(VulkanLayer::Validation);
288         }
289 
290         // Always use the Fuchsia swapchain layer if available.
291         UseLayerIfAvailable(VulkanLayer::FuchsiaImagePipeSwapchain);
292 
293         // Available and known instance extensions default to being requested, but some special
294         // cases are removed.
295         usedKnobs.extensions = extensionsToRequest;
296 
297         std::vector<const char*> extensionNames;
298         for (InstanceExt ext : IterateBitSet(extensionsToRequest)) {
299             const InstanceExtInfo& info = GetInstanceExtInfo(ext);
300 
301             if (info.versionPromoted > mGlobalInfo.apiVersion) {
302                 extensionNames.push_back(info.name);
303             }
304         }
305 
306         VkApplicationInfo appInfo;
307         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
308         appInfo.pNext = nullptr;
309         appInfo.pApplicationName = nullptr;
310         appInfo.applicationVersion = 0;
311         appInfo.pEngineName = nullptr;
312         appInfo.engineVersion = 0;
313         // Vulkan 1.0 implementations were required to return VK_ERROR_INCOMPATIBLE_DRIVER if
314         // apiVersion was larger than 1.0. Meanwhile, as long as the instance supports at least
315         // Vulkan 1.1, an application can use different versions of Vulkan with an instance than
316         // it does with a device or physical device. So we should set apiVersion to Vulkan 1.0
317         // if the instance only supports Vulkan 1.0. Otherwise we set apiVersion to Vulkan 1.2,
318         // treat 1.2 as the highest API version dawn targets.
319         if (mGlobalInfo.apiVersion == VK_MAKE_VERSION(1, 0, 0)) {
320             appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
321         } else {
322             appInfo.apiVersion = VK_MAKE_VERSION(1, 2, 0);
323         }
324 
325         VkInstanceCreateInfo createInfo;
326         createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
327         createInfo.pNext = nullptr;
328         createInfo.flags = 0;
329         createInfo.pApplicationInfo = &appInfo;
330         createInfo.enabledLayerCount = static_cast<uint32_t>(layerNames.size());
331         createInfo.ppEnabledLayerNames = layerNames.data();
332         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensionNames.size());
333         createInfo.ppEnabledExtensionNames = extensionNames.data();
334 
335         PNextChainBuilder createInfoChain(&createInfo);
336 
337         // Register the debug callback for instance creation so we receive message for any errors
338         // (validation or other).
339         VkDebugUtilsMessengerCreateInfoEXT utilsMessengerCreateInfo;
340         if (usedKnobs.HasExt(InstanceExt::DebugUtils)) {
341             utilsMessengerCreateInfo.flags = 0;
342             utilsMessengerCreateInfo.messageSeverity =
343                 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
344                 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
345             utilsMessengerCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
346                                                    VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
347             utilsMessengerCreateInfo.pfnUserCallback = OnInstanceCreationDebugUtilsCallback;
348             utilsMessengerCreateInfo.pUserData = nullptr;
349 
350             createInfoChain.Add(&utilsMessengerCreateInfo,
351                                 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT);
352         }
353 
354         // Try to turn on synchronization validation if the instance was created with backend
355         // validation enabled.
356         VkValidationFeaturesEXT validationFeatures;
357         VkValidationFeatureEnableEXT kEnableSynchronizationValidation =
358             VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT;
359         if (instance->IsBackendValidationEnabled() &&
360             usedKnobs.HasExt(InstanceExt::ValidationFeatures)) {
361             validationFeatures.enabledValidationFeatureCount = 1;
362             validationFeatures.pEnabledValidationFeatures = &kEnableSynchronizationValidation;
363             validationFeatures.disabledValidationFeatureCount = 0;
364             validationFeatures.pDisabledValidationFeatures = nullptr;
365 
366             createInfoChain.Add(&validationFeatures, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT);
367         }
368 
369         DAWN_TRY(CheckVkSuccess(mFunctions.CreateInstance(&createInfo, nullptr, &mInstance),
370                                 "vkCreateInstance"));
371 
372         return usedKnobs;
373     }
374 
RegisterDebugUtils()375     MaybeError VulkanInstance::RegisterDebugUtils() {
376         VkDebugUtilsMessengerCreateInfoEXT createInfo;
377         createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
378         createInfo.pNext = nullptr;
379         createInfo.flags = 0;
380         createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
381                                      VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
382         createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
383                                  VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
384         createInfo.pfnUserCallback = OnDebugUtilsCallback;
385         createInfo.pUserData = nullptr;
386 
387         return CheckVkSuccess(mFunctions.CreateDebugUtilsMessengerEXT(
388                                   mInstance, &createInfo, nullptr, &*mDebugUtilsMessenger),
389                               "vkCreateDebugUtilsMessengerEXT");
390     }
391 
Backend(InstanceBase * instance)392     Backend::Backend(InstanceBase* instance)
393         : BackendConnection(instance, wgpu::BackendType::Vulkan) {
394     }
395 
396     Backend::~Backend() = default;
397 
DiscoverDefaultAdapters()398     std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
399         AdapterDiscoveryOptions options;
400         auto result = DiscoverAdapters(&options);
401         if (result.IsError()) {
402             GetInstance()->ConsumedError(result.AcquireError());
403             return {};
404         }
405         return result.AcquireSuccess();
406     }
407 
DiscoverAdapters(const AdapterDiscoveryOptionsBase * optionsBase)408     ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
409         const AdapterDiscoveryOptionsBase* optionsBase) {
410         ASSERT(optionsBase->backendType == WGPUBackendType_Vulkan);
411 
412         const AdapterDiscoveryOptions* options =
413             static_cast<const AdapterDiscoveryOptions*>(optionsBase);
414 
415         std::vector<std::unique_ptr<AdapterBase>> adapters;
416 
417         InstanceBase* instance = GetInstance();
418         for (ICD icd : kICDs) {
419             if (options->forceSwiftShader && icd != ICD::SwiftShader) {
420                 continue;
421             }
422             if (mVulkanInstances[icd] == nullptr && instance->ConsumedError([&]() -> MaybeError {
423                     DAWN_TRY_ASSIGN(mVulkanInstances[icd], VulkanInstance::Create(instance, icd));
424                     return {};
425                 }())) {
426                 // Instance failed to initialize.
427                 continue;
428             }
429             const std::vector<VkPhysicalDevice>& physicalDevices =
430                 mVulkanInstances[icd]->GetPhysicalDevices();
431             for (uint32_t i = 0; i < physicalDevices.size(); ++i) {
432                 std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
433                     instance, mVulkanInstances[icd].Get(), physicalDevices[i]);
434                 if (instance->ConsumedError(adapter->Initialize())) {
435                     continue;
436                 }
437                 adapters.push_back(std::move(adapter));
438             }
439         }
440         return adapters;
441     }
442 
Connect(InstanceBase * instance)443     BackendConnection* Connect(InstanceBase* instance) {
444         return new Backend(instance);
445     }
446 
447 }}  // namespace dawn_native::vulkan
448