xref: /aosp_15_r20/external/skia/tools/gpu/vk/VkTestHelper.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2020 Google Inc.
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 "tools/gpu/vk/VkTestHelper.h"
9 
10 #if defined(SK_VULKAN)
11 
12 #include "include/core/SkSurface.h"
13 #include "include/gpu/ganesh/GrTypes.h"
14 #include "include/gpu/vk/VulkanBackendContext.h"
15 #include "include/gpu/vk/VulkanMemoryAllocator.h"
16 #include "tests/TestType.h"
17 #include "tools/gpu/ProtectedUtils.h"
18 #include "tools/gpu/vk/VkTestUtils.h"
19 
20 #if defined(SK_GANESH)
21 #include "include/gpu/ganesh/GrDirectContext.h"
22 #include "include/gpu/ganesh/vk/GrVkDirectContext.h"
23 #endif
24 
25 #if defined(SK_GRAPHITE)
26 #include "include/gpu/graphite/Context.h"
27 #include "include/gpu/graphite/vk/VulkanGraphiteUtils.h"
28 #include "src/gpu/graphite/ContextOptionsPriv.h"
29 #endif
30 
31 #define ACQUIRE_INST_VK_PROC(name)                                                               \
32     fVk##name = reinterpret_cast<PFN_vk##name>(instProc(fBackendContext.fInstance, "vk" #name)); \
33     if (fVk##name == nullptr) {                                                                  \
34         SkDebugf("Function ptr for vk%s could not be acquired\n", #name);                        \
35         return false;                                                                            \
36     }
37 
38 #define ACQUIRE_DEVICE_VK_PROC(name)                                                          \
39     fVk##name = reinterpret_cast<PFN_vk##name>(fVkGetDeviceProcAddr(fDevice, "vk" #name));    \
40     if (fVk##name == nullptr) {                                                               \
41         SkDebugf("Function ptr for vk%s could not be acquired\n", #name);                     \
42         return false;                                                                         \
43     }
44 
45 #if defined(SK_GANESH)
46 
47 class GaneshVkTestHelper : public VkTestHelper {
48 public:
GaneshVkTestHelper(bool isProtected)49     GaneshVkTestHelper(bool isProtected) : VkTestHelper(isProtected) {}
50 
~GaneshVkTestHelper()51     ~GaneshVkTestHelper() override {
52         // Make sure any work, release procs, etc left on the context are finished with before we
53         // start tearing everything down.
54         if (fDirectContext) {
55             fDirectContext->flushAndSubmit(GrSyncCpu::kYes);
56         }
57 
58         fDirectContext.reset();
59     }
60 
isValid() const61     bool isValid() const override { return fDirectContext != nullptr; }
62 
createSurface(SkISize size,bool textureable,bool isProtected)63     sk_sp<SkSurface> createSurface(SkISize size, bool textureable, bool isProtected) override {
64         // Make Ganesh use DMSAA to better match Graphite's behavior
65         SkSurfaceProps props(SkSurfaceProps::kDynamicMSAA_Flag, kUnknown_SkPixelGeometry);
66 
67         return ProtectedUtils::CreateProtectedSkSurface(fDirectContext.get(), size,
68                                                         textureable, isProtected,
69                                                         &props);
70     }
71 
submitAndWaitForCompletion(bool * completionMarker)72     void submitAndWaitForCompletion(bool* completionMarker) override {
73         fDirectContext->submit();
74         while (!*completionMarker) {
75             fDirectContext->checkAsyncWorkCompletion();
76         }
77     }
78 
directContext()79     GrDirectContext* directContext() override { return fDirectContext.get(); }
80 
81 protected:
init()82     bool init() override {
83         if (!this->setupBackendContext()) {
84             return false;
85         }
86 
87         SkASSERT(fBackendContext.fMemoryAllocator);
88         fDirectContext = GrDirectContexts::MakeVulkan(fBackendContext);
89         if (!fDirectContext) {
90             return false;
91         }
92 
93         SkASSERT(fDirectContext->supportsProtectedContent() == fIsProtected);
94         return true;
95     }
96 
97 private:
98     sk_sp<GrDirectContext> fDirectContext;
99 };
100 
101 #endif // SK_GANESH
102 
103 #if defined(SK_GRAPHITE)
104 
105 class GraphiteVkTestHelper : public VkTestHelper {
106 public:
GraphiteVkTestHelper(bool isProtected)107     GraphiteVkTestHelper(bool isProtected) : VkTestHelper(isProtected) {}
108 
~GraphiteVkTestHelper()109     ~GraphiteVkTestHelper() override {
110         // Make sure any work, release procs, etc left on the context are finished with before we
111         // start tearing everything down.
112 
113         std::unique_ptr<skgpu::graphite::Recording> recording;
114         if (fRecorder) {
115             recording = fRecorder->snap();
116         }
117 
118         if (fContext) {
119             fContext->insertRecording({ recording.get() });
120             fContext->submit(skgpu::graphite::SyncToCpu::kYes);
121         }
122 
123         recording.reset();
124         fRecorder.reset();
125         fContext.reset();
126     }
127 
isValid() const128     bool isValid() const override { return fContext != nullptr && fRecorder != nullptr; }
129 
createSurface(SkISize size,bool,bool isProtected)130     sk_sp<SkSurface> createSurface(SkISize size,
131                                    bool /* textureable */,
132                                    bool isProtected) override {
133         return ProtectedUtils::CreateProtectedSkSurface(fRecorder.get(), size,
134                                                         skgpu::Protected(isProtected));
135     }
136 
submitAndWaitForCompletion(bool * completionMarker)137     void submitAndWaitForCompletion(bool* completionMarker) override {
138         fContext->submit();
139         while (!*completionMarker) {
140             fContext->checkAsyncWorkCompletion();
141         }
142     }
143 
recorder()144     skgpu::graphite::Recorder* recorder() override { return fRecorder.get(); }
context()145     skgpu::graphite::Context* context() override { return fContext.get(); }
146 
147 protected:
init()148     bool init() override {
149         if (!this->setupBackendContext()) {
150             return false;
151         }
152 
153         skgpu::graphite::ContextOptions contextOptions;
154         skgpu::graphite::ContextOptionsPriv contextOptionsPriv;
155         // Needed to make ManagedGraphiteTexture::ReleaseProc (w/in CreateProtectedSkSurface) work
156         contextOptionsPriv.fStoreContextRefInRecorder = true;
157         contextOptions.fOptionsPriv = &contextOptionsPriv;
158 
159         fContext = skgpu::graphite::ContextFactory::MakeVulkan(fBackendContext, contextOptions);
160         if (!fContext) {
161             return false;
162         }
163 
164         SkASSERT(fContext->supportsProtectedContent() == fIsProtected);
165 
166         fRecorder = fContext->makeRecorder();
167         if (!fRecorder) {
168             return false;
169         }
170 
171         return true;
172     }
173 
174 private:
175     std::unique_ptr<skgpu::graphite::Context> fContext;
176     std::unique_ptr<skgpu::graphite::Recorder> fRecorder;
177 };
178 
179 #endif // SK_GRAPHITE
180 
Make(skiatest::TestType testType,bool isProtected)181 std::unique_ptr<VkTestHelper> VkTestHelper::Make(skiatest::TestType testType,
182                                                  bool isProtected) {
183     std::unique_ptr<VkTestHelper> helper;
184 
185     switch (testType) {
186 #if defined(SK_GANESH)
187         case skiatest::TestType::kGanesh:
188             helper = std::make_unique<GaneshVkTestHelper>(isProtected);
189             break;
190 #endif
191 #if defined(SK_GRAPHITE)
192         case skiatest::TestType::kGraphite:
193             helper = std::make_unique<GraphiteVkTestHelper>(isProtected);
194             break;
195 #endif
196         default:
197             return nullptr;
198     }
199     if (!helper->init()) {
200         return nullptr;
201     }
202 
203     return helper;
204 }
205 
setupBackendContext()206 bool VkTestHelper::setupBackendContext() {
207     PFN_vkGetInstanceProcAddr instProc;
208     if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc)) {
209         return false;
210     }
211 
212     fFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
213     fFeatures.pNext = nullptr;
214 
215     fBackendContext.fInstance = VK_NULL_HANDLE;
216     fBackendContext.fDevice = VK_NULL_HANDLE;
217 
218     if (!sk_gpu_test::CreateVkBackendContext(instProc, &fBackendContext, &fExtensions,
219                                              &fFeatures, &fDebugCallback, nullptr,
220                                              sk_gpu_test::CanPresentFn(), fIsProtected)) {
221         return false;
222     }
223     fDevice = fBackendContext.fDevice;
224 
225     if (fDebugCallback != VK_NULL_HANDLE) {
226         fDestroyDebugCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
227                 instProc(fBackendContext.fInstance, "vkDestroyDebugReportCallbackEXT"));
228     }
229     ACQUIRE_INST_VK_PROC(DestroyInstance)
230     ACQUIRE_INST_VK_PROC(DeviceWaitIdle)
231     ACQUIRE_INST_VK_PROC(DestroyDevice)
232 
233     ACQUIRE_INST_VK_PROC(GetPhysicalDeviceFormatProperties)
234     ACQUIRE_INST_VK_PROC(GetPhysicalDeviceMemoryProperties)
235 
236     ACQUIRE_INST_VK_PROC(GetDeviceProcAddr)
237 
238     ACQUIRE_DEVICE_VK_PROC(CreateImage)
239     ACQUIRE_DEVICE_VK_PROC(DestroyImage)
240     ACQUIRE_DEVICE_VK_PROC(GetImageMemoryRequirements)
241     ACQUIRE_DEVICE_VK_PROC(AllocateMemory)
242     ACQUIRE_DEVICE_VK_PROC(FreeMemory)
243     ACQUIRE_DEVICE_VK_PROC(BindImageMemory)
244     ACQUIRE_DEVICE_VK_PROC(MapMemory)
245     ACQUIRE_DEVICE_VK_PROC(UnmapMemory)
246     ACQUIRE_DEVICE_VK_PROC(FlushMappedMemoryRanges)
247     ACQUIRE_DEVICE_VK_PROC(GetImageSubresourceLayout)
248     return true;
249 }
250 
~VkTestHelper()251 VkTestHelper::~VkTestHelper() {
252     fBackendContext.fMemoryAllocator.reset();
253     if (fDevice != VK_NULL_HANDLE) {
254         fVkDeviceWaitIdle(fDevice);
255         fVkDestroyDevice(fDevice, nullptr);
256         fDevice = VK_NULL_HANDLE;
257     }
258     if (fDebugCallback != VK_NULL_HANDLE) {
259         fDestroyDebugCallback(fBackendContext.fInstance, fDebugCallback, nullptr);
260     }
261 
262     if (fBackendContext.fInstance != VK_NULL_HANDLE) {
263         fVkDestroyInstance(fBackendContext.fInstance, nullptr);
264         fBackendContext.fInstance = VK_NULL_HANDLE;
265     }
266 
267     sk_gpu_test::FreeVulkanFeaturesStructs(&fFeatures);
268 }
269 
270 #endif // SK_VULKAN
271