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