1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
9
10 #include "include/gpu/GpuTypes.h"
11 #include "include/gpu/graphite/ContextOptions.h"
12 #include "include/gpu/vk/VulkanBackendContext.h"
13 #include "include/gpu/vk/VulkanExtensions.h"
14 #include "include/private/base/SkMutex.h"
15 #include "src/gpu/GpuTypesPriv.h"
16 #include "src/gpu/graphite/Log.h"
17 #include "src/gpu/graphite/ResourceTypes.h"
18 #include "src/gpu/graphite/vk/VulkanBuffer.h"
19 #include "src/gpu/graphite/vk/VulkanCaps.h"
20 #include "src/gpu/graphite/vk/VulkanResourceProvider.h"
21 #include "src/gpu/vk/VulkanInterface.h"
22 #include "src/gpu/vk/VulkanUtilsPriv.h"
23
24 #if defined(SK_USE_VMA)
25 #include "src/gpu/vk/vulkanmemoryallocator/VulkanMemoryAllocatorPriv.h"
26 #endif
27
28 namespace skgpu::graphite {
29
Make(const VulkanBackendContext & context,const ContextOptions & options)30 sk_sp<SharedContext> VulkanSharedContext::Make(const VulkanBackendContext& context,
31 const ContextOptions& options) {
32 if (context.fInstance == VK_NULL_HANDLE ||
33 context.fPhysicalDevice == VK_NULL_HANDLE ||
34 context.fDevice == VK_NULL_HANDLE ||
35 context.fQueue == VK_NULL_HANDLE) {
36 SKGPU_LOG_E("Failed to create VulkanSharedContext because either fInstance,"
37 "fPhysicalDevice, fDevice, or fQueue in the VulkanBackendContext is"
38 "VK_NULL_HANDLE.");
39 return nullptr;
40 }
41 if (!context.fGetProc) {
42 SKGPU_LOG_E("Failed to create VulkanSharedContext because there is no valid VulkanGetProc"
43 "on the VulkanBackendContext");
44 return nullptr;
45 }
46 // If no extensions are provided, make sure we don't have a null dereference downstream.
47 skgpu::VulkanExtensions noExtensions;
48 const skgpu::VulkanExtensions* extensions = &noExtensions;
49 if (context.fVkExtensions) {
50 extensions = context.fVkExtensions;
51 }
52
53 uint32_t physDevVersion = 0;
54 sk_sp<const skgpu::VulkanInterface> interface =
55 skgpu::MakeInterface(context, extensions, &physDevVersion, nullptr);
56 if (!interface) {
57 SKGPU_LOG_E("Failed to create VulkanInterface.");
58 return nullptr;
59 }
60
61 VkPhysicalDeviceFeatures2 features;
62 const VkPhysicalDeviceFeatures2* featuresPtr;
63 // If fDeviceFeatures2 is not null, then we ignore fDeviceFeatures. If both are null, we assume
64 // no features are enabled.
65 if (!context.fDeviceFeatures2 && context.fDeviceFeatures) {
66 features.pNext = nullptr;
67 features.features = *context.fDeviceFeatures;
68 featuresPtr = &features;
69 } else {
70 featuresPtr = context.fDeviceFeatures2;
71 }
72
73 std::unique_ptr<const VulkanCaps> caps(new VulkanCaps(options,
74 interface.get(),
75 context.fPhysicalDevice,
76 physDevVersion,
77 featuresPtr,
78 extensions,
79 context.fProtectedContext));
80
81 sk_sp<skgpu::VulkanMemoryAllocator> memoryAllocator = context.fMemoryAllocator;
82 #if defined(SK_USE_VMA)
83 if (!memoryAllocator) {
84 // We were not given a memory allocator at creation
85 skgpu::ThreadSafe threadSafe = options.fClientWillExternallySynchronizeAllThreads
86 ? skgpu::ThreadSafe::kNo
87 : skgpu::ThreadSafe::kYes;
88 memoryAllocator = skgpu::VulkanMemoryAllocators::Make(context,
89 threadSafe,
90 options.fVulkanVMALargeHeapBlockSize);
91 }
92 #endif
93 if (!memoryAllocator) {
94 SKGPU_LOG_E("No supplied vulkan memory allocator and unable to create one internally.");
95 return nullptr;
96 }
97
98 return sk_sp<SharedContext>(new VulkanSharedContext(context,
99 std::move(interface),
100 std::move(memoryAllocator),
101 std::move(caps),
102 options.fUserDefinedKnownRuntimeEffects));
103 }
104
VulkanSharedContext(const VulkanBackendContext & backendContext,sk_sp<const skgpu::VulkanInterface> interface,sk_sp<skgpu::VulkanMemoryAllocator> memoryAllocator,std::unique_ptr<const VulkanCaps> caps,SkSpan<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects)105 VulkanSharedContext::VulkanSharedContext(
106 const VulkanBackendContext& backendContext,
107 sk_sp<const skgpu::VulkanInterface> interface,
108 sk_sp<skgpu::VulkanMemoryAllocator> memoryAllocator,
109 std::unique_ptr<const VulkanCaps> caps,
110 SkSpan<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects)
111 : SharedContext(std::move(caps), BackendApi::kVulkan, userDefinedKnownRuntimeEffects)
112 , fInterface(std::move(interface))
113 , fMemoryAllocator(std::move(memoryAllocator))
114 , fPhysDevice(backendContext.fPhysicalDevice)
115 , fDevice(backendContext.fDevice)
116 , fQueueIndex(backendContext.fGraphicsQueueIndex)
117 , fDeviceLostContext(backendContext.fDeviceLostContext)
118 , fDeviceLostProc(backendContext.fDeviceLostProc) {}
119
~VulkanSharedContext()120 VulkanSharedContext::~VulkanSharedContext() {
121 // need to clear out resources before the allocator is removed
122 this->globalCache()->deleteResources();
123 }
124
makeResourceProvider(SingleOwner * singleOwner,uint32_t recorderID,size_t resourceBudget)125 std::unique_ptr<ResourceProvider> VulkanSharedContext::makeResourceProvider(
126 SingleOwner* singleOwner,
127 uint32_t recorderID,
128 size_t resourceBudget) {
129 return std::unique_ptr<ResourceProvider>(
130 new VulkanResourceProvider(this,
131 singleOwner,
132 recorderID,
133 resourceBudget));
134 }
135
checkVkResult(VkResult result) const136 bool VulkanSharedContext::checkVkResult(VkResult result) const {
137 switch (result) {
138 case VK_SUCCESS:
139 return true;
140 case VK_ERROR_DEVICE_LOST:
141 {
142 SkAutoMutexExclusive lock(fDeviceIsLostMutex);
143 if (fDeviceIsLost) {
144 return false;
145 }
146 fDeviceIsLost = true;
147 // Fall through to InvokeDeviceLostCallback (on first VK_ERROR_DEVICE_LOST) only afer
148 // releasing fDeviceIsLostMutex, otherwise clients might cause deadlock by checking
149 // isDeviceLost() from the callback.
150 }
151 skgpu::InvokeDeviceLostCallback(interface(),
152 device(),
153 fDeviceLostContext,
154 fDeviceLostProc,
155 vulkanCaps().supportsDeviceFaultInfo());
156 return false;
157 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
158 case VK_ERROR_OUT_OF_HOST_MEMORY:
159 // TODO: determine how we'll track this in a thread-safe manner
160 //this->setOOMed();
161 return false;
162 default:
163 return false;
164 }
165 }
166 } // namespace skgpu::graphite
167