1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // #define LOG_NDEBUG 0
18 #undef LOG_TAG
19 #define LOG_TAG "RenderEngine"
20 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21 
22 #include "SkiaVkRenderEngine.h"
23 
24 #include "GaneshVkRenderEngine.h"
25 #include "compat/SkiaGpuContext.h"
26 
27 #include <GrBackendSemaphore.h>
28 #include <GrContextOptions.h>
29 #include <GrDirectContext.h>
30 #include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
31 #include <include/gpu/ganesh/vk/GrVkDirectContext.h>
32 #include <vk/GrVkExtensions.h>
33 #include <vk/GrVkTypes.h>
34 
35 #include <android-base/stringprintf.h>
36 #include <gui/TraceUtils.h>
37 #include <sync/sync.h>
38 #include <utils/Trace.h>
39 
40 #include <memory>
41 #include <string>
42 
43 #include <vulkan/vulkan.h>
44 #include "log/log_main.h"
45 
46 namespace android {
47 namespace renderengine {
48 
49 static skia::VulkanInterface sVulkanInterface;
50 static skia::VulkanInterface sProtectedContentVulkanInterface;
51 
sSetupVulkanInterface()52 static void sSetupVulkanInterface() {
53     if (!sVulkanInterface.isInitialized()) {
54         sVulkanInterface.init(false /* no protected content */);
55         // We will have to abort if non-protected VkDevice creation fails (then nothing works).
56         LOG_ALWAYS_FATAL_IF(!sVulkanInterface.isInitialized(),
57                             "Could not initialize Vulkan RenderEngine!");
58     }
59     if (!sProtectedContentVulkanInterface.isInitialized()) {
60         sProtectedContentVulkanInterface.init(true /* protected content */);
61         if (!sProtectedContentVulkanInterface.isInitialized()) {
62             ALOGE("Could not initialize protected content Vulkan RenderEngine.");
63         }
64     }
65 }
66 
canSupport(GraphicsApi graphicsApi)67 bool RenderEngine::canSupport(GraphicsApi graphicsApi) {
68     switch (graphicsApi) {
69         case GraphicsApi::GL:
70             return true;
71         case GraphicsApi::VK: {
72             // Static local variables are initialized once, on first invocation of the function.
73             static const bool canSupportVulkan = []() {
74                 if (!sVulkanInterface.isInitialized()) {
75                     sVulkanInterface.init(false /* no protected content */);
76                     ALOGD("%s: initialized == %s.", __func__,
77                           sVulkanInterface.isInitialized() ? "true" : "false");
78                     if (!sVulkanInterface.isInitialized()) {
79                         sVulkanInterface.teardown();
80                         return false;
81                     }
82                 }
83                 return true;
84             }();
85             return canSupportVulkan;
86         }
87     }
88 }
89 
teardown(GraphicsApi graphicsApi)90 void RenderEngine::teardown(GraphicsApi graphicsApi) {
91     switch (graphicsApi) {
92         case GraphicsApi::GL:
93             break;
94         case GraphicsApi::VK: {
95             if (sVulkanInterface.isInitialized()) {
96                 sVulkanInterface.teardown();
97                 ALOGD("Tearing down the unprotected VulkanInterface.");
98             }
99             if (sProtectedContentVulkanInterface.isInitialized()) {
100                 sProtectedContentVulkanInterface.teardown();
101                 ALOGD("Tearing down the protected VulkanInterface.");
102             }
103             break;
104         }
105     }
106 }
107 
108 namespace skia {
109 
110 using base::StringAppendF;
111 
SkiaVkRenderEngine(const RenderEngineCreationArgs & args)112 SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
113       : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
114                          args.blurAlgorithm) {}
115 
~SkiaVkRenderEngine()116 SkiaVkRenderEngine::~SkiaVkRenderEngine() {
117     finishRenderingAndAbandonContexts();
118     // Teardown VulkanInterfaces after Skia contexts have been abandoned
119     teardown(GraphicsApi::VK);
120 }
121 
createContexts()122 SkiaRenderEngine::Contexts SkiaVkRenderEngine::createContexts() {
123     sSetupVulkanInterface();
124     // More work would need to be done in order to have multiple RenderEngine instances. In
125     // particular, they would not be able to share the same VulkanInterface(s).
126     LOG_ALWAYS_FATAL_IF(!sVulkanInterface.takeOwnership(),
127                         "SkiaVkRenderEngine couldn't take ownership of existing unprotected "
128                         "VulkanInterface! Only one SkiaVkRenderEngine instance may exist at a "
129                         "time.");
130     if (sProtectedContentVulkanInterface.isInitialized()) {
131         // takeOwnership fails on an uninitialized VulkanInterface, but protected content support is
132         // optional.
133         LOG_ALWAYS_FATAL_IF(!sProtectedContentVulkanInterface.takeOwnership(),
134                             "SkiaVkRenderEngine couldn't take ownership of existing protected "
135                             "VulkanInterface! Only one SkiaVkRenderEngine instance may exist at a "
136                             "time.");
137     }
138 
139     SkiaRenderEngine::Contexts contexts;
140     contexts.first = createContext(sVulkanInterface);
141     if (supportsProtectedContentImpl()) {
142         contexts.second = createContext(sProtectedContentVulkanInterface);
143     }
144 
145     return contexts;
146 }
147 
supportsProtectedContentImpl() const148 bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
149     return sProtectedContentVulkanInterface.isInitialized();
150 }
151 
useProtectedContextImpl(GrProtected)152 bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
153     return true;
154 }
155 
getVulkanInterface(bool protectedContext)156 VulkanInterface& SkiaVkRenderEngine::getVulkanInterface(bool protectedContext) {
157     if (protectedContext) {
158         return sProtectedContentVulkanInterface;
159     }
160     return sVulkanInterface;
161 }
162 
getContextPriority()163 int SkiaVkRenderEngine::getContextPriority() {
164     // EGL_CONTEXT_PRIORITY_REALTIME_NV
165     constexpr int kRealtimePriority = 0x3357;
166     if (getVulkanInterface(isProtected()).isRealtimePriority()) {
167         return kRealtimePriority;
168     } else {
169         return 0;
170     }
171 }
172 
appendBackendSpecificInfoToDump(std::string & result)173 void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
174     StringAppendF(&result, "\n ------------RE Vulkan----------\n");
175     StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.isInitialized());
176     StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
177                   sProtectedContentVulkanInterface.isInitialized());
178 
179     if (!sVulkanInterface.isInitialized()) {
180         return;
181     }
182 
183     StringAppendF(&result, "\n Instance extensions:\n");
184     for (const auto& name : sVulkanInterface.getInstanceExtensionNames()) {
185         StringAppendF(&result, "\n %s\n", name.c_str());
186     }
187 
188     StringAppendF(&result, "\n Device extensions:\n");
189     for (const auto& name : sVulkanInterface.getDeviceExtensionNames()) {
190         StringAppendF(&result, "\n %s\n", name.c_str());
191     }
192 }
193 
194 } // namespace skia
195 } // namespace renderengine
196 } // namespace android
197