• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkSurface.h"
15 #include "include/core/SkTypes.h"
16 #include "include/gpu/GrDirectContext.h"
17 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
18 #include "include/gpu/ganesh/vk/GrVkDirectContext.h"
19 #include "include/gpu/vk/VulkanBackendContext.h"
20 #include "include/gpu/vk/VulkanExtensions.h"
21 #include "tools/gpu/vk/VkTestUtils.h"
22 
23 #include <string.h>
24 #include <vulkan/vulkan_core.h>
25 #include <functional>
26 #include <memory>
27 
28 #define ACQUIRE_INST_VK_PROC(name)                                                           \
29     do {                                                                                     \
30     fVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, backendContext.fInstance, \
31                                                        VK_NULL_HANDLE));                     \
32     if (fVk##name == nullptr) {                                                              \
33         SkDebugf("Function ptr for vk%s could not be acquired\n", #name);                    \
34         return 1;                                                                            \
35     }                                                                                        \
36     } while(false)
37 
main(int argc,char ** argv)38 int main(int argc, char** argv) {
39     skgpu::VulkanBackendContext backendContext;
40     VkDebugReportCallbackEXT debugCallback;
41     std::unique_ptr<skgpu::VulkanExtensions> extensions(new skgpu::VulkanExtensions());
42     std::unique_ptr<VkPhysicalDeviceFeatures2> features(new VkPhysicalDeviceFeatures2);
43 
44     // First we need to create a VulkanBackendContext so that we can make a Vulkan GrDirectContext.
45     // The vast majority of this chunk of code is setting up the VkInstance and VkDevice objects.
46     // Normally a client will have their own way of creating these objects. This example uses Skia's
47     // test helper sk_gpu_test::CreateVkBackendContext to aid in this. Clients can look at this
48     // function as a guide on things to consider when setting up Vulkan for themselves, but they
49     // should not depend on that function. We may arbitrarily change it as it is meant only for Skia
50     // internal testing. Additionally it may do some odd things that a normal Vulkan user wouldn't
51     // do because it is only meant for Skia testing.
52     {
53         PFN_vkGetInstanceProcAddr instProc;
54         if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc)) {
55             return 1;
56         }
57 
58         memset(features.get(), 0, sizeof(VkPhysicalDeviceFeatures2));
59         features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
60         features->pNext = nullptr;
61         // Fill in features you want to enable here
62 
63         backendContext.fInstance = VK_NULL_HANDLE;
64         backendContext.fDevice = VK_NULL_HANDLE;
65 
66         if (!sk_gpu_test::CreateVkBackendContext(instProc, &backendContext, extensions.get(),
67                                                  features.get(), &debugCallback)) {
68             return 1;
69         }
70     }
71 
72     auto getProc = backendContext.fGetProc;
73     PFN_vkDestroyInstance fVkDestroyInstance;
74     PFN_vkDestroyDebugReportCallbackEXT fVkDestroyDebugReportCallbackEXT = nullptr;
75     PFN_vkDestroyDevice fVkDestroyDevice;
76     ACQUIRE_INST_VK_PROC(DestroyInstance);
77     if (debugCallback != VK_NULL_HANDLE) {
78         ACQUIRE_INST_VK_PROC(DestroyDebugReportCallbackEXT);
79     }
80     ACQUIRE_INST_VK_PROC(DestroyDevice);
81 
82     // Create a GrDirectContext with our VulkanBackendContext
83     sk_sp<GrDirectContext> context = GrDirectContexts::MakeVulkan(backendContext);
84     if (!context) {
85         fVkDestroyDevice(backendContext.fDevice, nullptr);
86         if (debugCallback != VK_NULL_HANDLE) {
87             fVkDestroyDebugReportCallbackEXT(backendContext.fInstance, debugCallback, nullptr);
88         }
89         fVkDestroyInstance(backendContext.fInstance, nullptr);
90         return 1;
91     }
92 
93     SkImageInfo imageInfo = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
94 
95     // Create an SkSurface backed by a Vulkan VkImage. Often clients will be getting VkImages from
96     // swapchains. In those cases they should use SkSurfaces::WrapBackendTexture or
97     // SkSurfaces::WrapBackendRenderTarget to wrap those premade VkImages in Skia. See the
98     // HelloWorld example app to see how this is done.
99     sk_sp<SkSurface> surface =
100             SkSurfaces::RenderTarget(context.get(), skgpu::Budgeted::kYes, imageInfo);
101     if (!surface) {
102         context.reset();
103         fVkDestroyDevice(backendContext.fDevice, nullptr);
104         if (debugCallback != VK_NULL_HANDLE) {
105             fVkDestroyDebugReportCallbackEXT(backendContext.fInstance, debugCallback, nullptr);
106         }        fVkDestroyInstance(backendContext.fInstance, nullptr);
107         return 1;
108     }
109 
110     surface->getCanvas()->clear(SK_ColorRED);
111 
112     // After drawing to our surface, we must first flush the recorded work (i.e. convert all our
113     // recorded SkCanvas calls into a VkCommandBuffer). Then we call submit to submit our
114     // VkCommandBuffers to the gpu queue.
115     context->flush(surface.get());
116     context->submit();
117 
118     surface.reset();
119     context.reset();
120 
121     // Skia doesn't own the VkDevice or VkInstance so the client must manage their lifetime. The
122     // client must not delete these objects until cleaning up all Skia objects that may have used
123     // them first.
124     fVkDestroyDevice(backendContext.fDevice, nullptr);
125     if (debugCallback != VK_NULL_HANDLE) {
126         fVkDestroyDebugReportCallbackEXT(backendContext.fInstance, debugCallback, nullptr);
127     }    fVkDestroyInstance(backendContext.fInstance, nullptr);
128     return 0;
129 }
130