xref: /aosp_15_r20/external/skia/src/gpu/graphite/vk/VulkanSharedContext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 }
103 
VulkanSharedContext(const VulkanBackendContext & backendContext,sk_sp<const skgpu::VulkanInterface> interface,sk_sp<skgpu::VulkanMemoryAllocator> memoryAllocator,std::unique_ptr<const VulkanCaps> caps)104 VulkanSharedContext::VulkanSharedContext(const VulkanBackendContext& backendContext,
105                                          sk_sp<const skgpu::VulkanInterface> interface,
106                                          sk_sp<skgpu::VulkanMemoryAllocator> memoryAllocator,
107                                          std::unique_ptr<const VulkanCaps> caps)
108         : skgpu::graphite::SharedContext(std::move(caps), BackendApi::kVulkan)
109         , fInterface(std::move(interface))
110         , fMemoryAllocator(std::move(memoryAllocator))
111         , fPhysDevice(backendContext.fPhysicalDevice)
112         , fDevice(backendContext.fDevice)
113         , fQueueIndex(backendContext.fGraphicsQueueIndex)
114         , fDeviceLostContext(backendContext.fDeviceLostContext)
115         , fDeviceLostProc(backendContext.fDeviceLostProc) {}
116 
~VulkanSharedContext()117 VulkanSharedContext::~VulkanSharedContext() {
118     // need to clear out resources before the allocator is removed
119     this->globalCache()->deleteResources();
120 }
121 
makeResourceProvider(SingleOwner * singleOwner,uint32_t recorderID,size_t resourceBudget,bool avoidBufferAlloc)122 std::unique_ptr<ResourceProvider> VulkanSharedContext::makeResourceProvider(
123         SingleOwner* singleOwner,
124         uint32_t recorderID,
125         size_t resourceBudget,
126         bool avoidBufferAlloc) {
127 
128     sk_sp<Buffer> intrinsicConstantBuffer;
129 
130     if (!avoidBufferAlloc) {
131         // Establish a uniform buffer that can be updated across multiple render passes and
132         // cmd buffers
133         size_t alignedIntrinsicConstantSize =
134                 std::max(VulkanResourceProvider::kIntrinsicConstantSize,
135                          this->vulkanCaps().requiredUniformBufferAlignment());
136         intrinsicConstantBuffer = VulkanBuffer::Make(
137                 this, alignedIntrinsicConstantSize, BufferType::kUniform, AccessPattern::kGpuOnly);
138         if (!intrinsicConstantBuffer) {
139             SKGPU_LOG_E("Failed to create intrinsic constant uniform buffer");
140             return nullptr;
141         }
142         SkASSERT(static_cast<VulkanBuffer*>(intrinsicConstantBuffer.get())->bufferUsageFlags()
143                  & VK_BUFFER_USAGE_TRANSFER_DST_BIT);
144         intrinsicConstantBuffer->setLabel("IntrinsicConstantBuffer");
145     }
146 
147     return std::unique_ptr<ResourceProvider>(
148             new VulkanResourceProvider(this,
149                                        singleOwner,
150                                        recorderID,
151                                        resourceBudget,
152                                        std::move(intrinsicConstantBuffer)));
153 }
154 
checkVkResult(VkResult result) const155 bool VulkanSharedContext::checkVkResult(VkResult result) const {
156     switch (result) {
157     case VK_SUCCESS:
158         return true;
159     case VK_ERROR_DEVICE_LOST:
160         {
161             SkAutoMutexExclusive lock(fDeviceIsLostMutex);
162             if (fDeviceIsLost) {
163                 return false;
164             }
165             fDeviceIsLost = true;
166             // Fall through to InvokeDeviceLostCallback (on first VK_ERROR_DEVICE_LOST) only afer
167             // releasing fDeviceIsLostMutex, otherwise clients might cause deadlock by checking
168             // isDeviceLost() from the callback.
169         }
170         skgpu::InvokeDeviceLostCallback(interface(),
171                                         device(),
172                                         fDeviceLostContext,
173                                         fDeviceLostProc,
174                                         vulkanCaps().supportsDeviceFaultInfo());
175         return false;
176     case VK_ERROR_OUT_OF_DEVICE_MEMORY:
177     case VK_ERROR_OUT_OF_HOST_MEMORY:
178         // TODO: determine how we'll track this in a thread-safe manner
179         //this->setOOMed();
180         return false;
181     default:
182         return false;
183     }
184 }
185 } // namespace skgpu::graphite
186