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