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