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/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/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 "include/private/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 fDirectContext = GrDirectContexts::MakeVulkan(fBackendContext);
88 if (!fDirectContext) {
89 return false;
90 }
91
92 SkASSERT(fDirectContext->supportsProtectedContent() == fIsProtected);
93 return true;
94 }
95
96 private:
97 sk_sp<GrDirectContext> fDirectContext;
98 };
99
100 #endif // SK_GANESH
101
102 #if defined(SK_GRAPHITE)
103
104 class GraphiteVkTestHelper : public VkTestHelper {
105 public:
GraphiteVkTestHelper(bool isProtected)106 GraphiteVkTestHelper(bool isProtected) : VkTestHelper(isProtected) {}
107
~GraphiteVkTestHelper()108 ~GraphiteVkTestHelper() override {
109 // Make sure any work, release procs, etc left on the context are finished with before we
110 // start tearing everything down.
111
112 std::unique_ptr<skgpu::graphite::Recording> recording;
113 if (fRecorder) {
114 recording = fRecorder->snap();
115 }
116
117 if (fContext) {
118 fContext->insertRecording({ recording.get() });
119 fContext->submit(skgpu::graphite::SyncToCpu::kYes);
120 }
121
122 recording.reset();
123 fRecorder.reset();
124 fContext.reset();
125 }
126
isValid() const127 bool isValid() const override { return fContext != nullptr && fRecorder != nullptr; }
128
createSurface(SkISize size,bool,bool isProtected)129 sk_sp<SkSurface> createSurface(SkISize size,
130 bool /* textureable */,
131 bool isProtected) override {
132 return ProtectedUtils::CreateProtectedSkSurface(fRecorder.get(), size,
133 skgpu::Protected(isProtected));
134 }
135
submitAndWaitForCompletion(bool * completionMarker)136 void submitAndWaitForCompletion(bool* completionMarker) override {
137 fContext->submit();
138 while (!*completionMarker) {
139 fContext->checkAsyncWorkCompletion();
140 }
141 }
142
recorder()143 skgpu::graphite::Recorder* recorder() override { return fRecorder.get(); }
144
145 protected:
init()146 bool init() override {
147 if (!this->setupBackendContext()) {
148 return false;
149 }
150
151 skgpu::graphite::ContextOptions contextOptions;
152 skgpu::graphite::ContextOptionsPriv contextOptionsPriv;
153 // Needed to make ManagedGraphiteTexture::ReleaseProc (w/in CreateProtectedSkSurface) work
154 contextOptionsPriv.fStoreContextRefInRecorder = true;
155 contextOptions.fOptionsPriv = &contextOptionsPriv;
156
157 fContext = skgpu::graphite::ContextFactory::MakeVulkan(fBackendContext, contextOptions);
158 if (!fContext) {
159 return false;
160 }
161
162 SkASSERT(fContext->supportsProtectedContent() == fIsProtected);
163
164 fRecorder = fContext->makeRecorder();
165 if (!fRecorder) {
166 return false;
167 }
168
169 return true;
170 }
171
172 private:
173 std::unique_ptr<skgpu::graphite::Context> fContext;
174 std::unique_ptr<skgpu::graphite::Recorder> fRecorder;
175 };
176
177 #endif // SK_GRAPHITE
178
Make(skiatest::TestType testType,bool isProtected)179 std::unique_ptr<VkTestHelper> VkTestHelper::Make(skiatest::TestType testType,
180 bool isProtected) {
181 std::unique_ptr<VkTestHelper> helper;
182
183 switch (testType) {
184 #if defined(SK_GANESH)
185 case skiatest::TestType::kGanesh:
186 helper = std::make_unique<GaneshVkTestHelper>(isProtected);
187 break;
188 #endif
189 #if defined(SK_GRAPHITE)
190 case skiatest::TestType::kGraphite:
191 helper = std::make_unique<GraphiteVkTestHelper>(isProtected);
192 break;
193 #endif
194 default:
195 return nullptr;
196 }
197 if (!helper->init()) {
198 return nullptr;
199 }
200
201 return helper;
202 }
203
setupBackendContext()204 bool VkTestHelper::setupBackendContext() {
205 PFN_vkGetInstanceProcAddr instProc;
206 if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc)) {
207 return false;
208 }
209
210 fFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
211 fFeatures.pNext = nullptr;
212
213 fBackendContext.fInstance = VK_NULL_HANDLE;
214 fBackendContext.fDevice = VK_NULL_HANDLE;
215
216 if (!sk_gpu_test::CreateVkBackendContext(instProc, &fBackendContext, &fExtensions,
217 &fFeatures, &fDebugCallback, nullptr,
218 sk_gpu_test::CanPresentFn(), fIsProtected)) {
219 return false;
220 }
221 fDevice = fBackendContext.fDevice;
222
223 if (fDebugCallback != VK_NULL_HANDLE) {
224 fDestroyDebugCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
225 instProc(fBackendContext.fInstance, "vkDestroyDebugReportCallbackEXT"));
226 }
227 ACQUIRE_INST_VK_PROC(DestroyInstance)
228 ACQUIRE_INST_VK_PROC(DeviceWaitIdle)
229 ACQUIRE_INST_VK_PROC(DestroyDevice)
230
231 ACQUIRE_INST_VK_PROC(GetPhysicalDeviceFormatProperties)
232 ACQUIRE_INST_VK_PROC(GetPhysicalDeviceMemoryProperties)
233
234 ACQUIRE_INST_VK_PROC(GetDeviceProcAddr)
235
236 ACQUIRE_DEVICE_VK_PROC(CreateImage)
237 ACQUIRE_DEVICE_VK_PROC(DestroyImage)
238 ACQUIRE_DEVICE_VK_PROC(GetImageMemoryRequirements)
239 ACQUIRE_DEVICE_VK_PROC(AllocateMemory)
240 ACQUIRE_DEVICE_VK_PROC(FreeMemory)
241 ACQUIRE_DEVICE_VK_PROC(BindImageMemory)
242 ACQUIRE_DEVICE_VK_PROC(MapMemory)
243 ACQUIRE_DEVICE_VK_PROC(UnmapMemory)
244 ACQUIRE_DEVICE_VK_PROC(FlushMappedMemoryRanges)
245 ACQUIRE_DEVICE_VK_PROC(GetImageSubresourceLayout)
246 return true;
247 }
248
~VkTestHelper()249 VkTestHelper::~VkTestHelper() {
250 fBackendContext.fMemoryAllocator.reset();
251 if (fDevice != VK_NULL_HANDLE) {
252 fVkDeviceWaitIdle(fDevice);
253 fVkDestroyDevice(fDevice, nullptr);
254 fDevice = VK_NULL_HANDLE;
255 }
256 if (fDebugCallback != VK_NULL_HANDLE) {
257 fDestroyDebugCallback(fBackendContext.fInstance, fDebugCallback, nullptr);
258 }
259
260 if (fBackendContext.fInstance != VK_NULL_HANDLE) {
261 fVkDestroyInstance(fBackendContext.fInstance, nullptr);
262 fBackendContext.fInstance = VK_NULL_HANDLE;
263 }
264
265 sk_gpu_test::FreeVulkanFeaturesStructs(&fFeatures);
266 }
267
268 #endif // SK_VULKAN
269