| /* |
| * Copyright 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // #define LOG_NDEBUG 0 |
| #undef LOG_TAG |
| #define LOG_TAG "RenderEngine" |
| #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| |
| #include "SkiaVkRenderEngine.h" |
| |
| #include "GaneshVkRenderEngine.h" |
| #include "compat/SkiaGpuContext.h" |
| |
| #include <GrBackendSemaphore.h> |
| #include <GrContextOptions.h> |
| #include <GrDirectContext.h> |
| #include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h> |
| #include <include/gpu/ganesh/vk/GrVkDirectContext.h> |
| #include <vk/GrVkTypes.h> |
| |
| #include <android-base/stringprintf.h> |
| #include <gui/TraceUtils.h> |
| #include <sync/sync.h> |
| #include <utils/Trace.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include <vulkan/vulkan.h> |
| #include "log/log_main.h" |
| |
| namespace android { |
| namespace renderengine { |
| |
| static skia::VulkanInterface sVulkanInterface; |
| static skia::VulkanInterface sProtectedContentVulkanInterface; |
| |
| static void sSetupVulkanInterface() { |
| if (!sVulkanInterface.isInitialized()) { |
| sVulkanInterface.init(false /* no protected content */); |
| // We will have to abort if non-protected VkDevice creation fails (then nothing works). |
| LOG_ALWAYS_FATAL_IF(!sVulkanInterface.isInitialized(), |
| "Could not initialize Vulkan RenderEngine!"); |
| } |
| if (!sProtectedContentVulkanInterface.isInitialized()) { |
| sProtectedContentVulkanInterface.init(true /* protected content */); |
| if (!sProtectedContentVulkanInterface.isInitialized()) { |
| ALOGE("Could not initialize protected content Vulkan RenderEngine."); |
| } |
| } |
| } |
| |
| bool RenderEngine::canSupport(GraphicsApi graphicsApi) { |
| switch (graphicsApi) { |
| case GraphicsApi::GL: |
| return true; |
| case GraphicsApi::VK: { |
| // Static local variables are initialized once, on first invocation of the function. |
| static const bool canSupportVulkan = []() { |
| if (!sVulkanInterface.isInitialized()) { |
| sVulkanInterface.init(false /* no protected content */); |
| ALOGD("%s: initialized == %s.", __func__, |
| sVulkanInterface.isInitialized() ? "true" : "false"); |
| if (!sVulkanInterface.isInitialized()) { |
| sVulkanInterface.teardown(); |
| return false; |
| } |
| } |
| return true; |
| }(); |
| return canSupportVulkan; |
| } |
| } |
| } |
| |
| void RenderEngine::teardown(GraphicsApi graphicsApi) { |
| switch (graphicsApi) { |
| case GraphicsApi::GL: |
| break; |
| case GraphicsApi::VK: { |
| if (sVulkanInterface.isInitialized()) { |
| sVulkanInterface.teardown(); |
| ALOGD("Tearing down the unprotected VulkanInterface."); |
| } |
| if (sProtectedContentVulkanInterface.isInitialized()) { |
| sProtectedContentVulkanInterface.teardown(); |
| ALOGD("Tearing down the protected VulkanInterface."); |
| } |
| break; |
| } |
| } |
| } |
| |
| namespace skia { |
| |
| using base::StringAppendF; |
| |
| SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args) |
| : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat), |
| args.blurAlgorithm) {} |
| |
| SkiaVkRenderEngine::~SkiaVkRenderEngine() { |
| finishRenderingAndAbandonContexts(); |
| // Teardown VulkanInterfaces after Skia contexts have been abandoned |
| teardown(GraphicsApi::VK); |
| } |
| |
| SkiaRenderEngine::Contexts SkiaVkRenderEngine::createContexts() { |
| sSetupVulkanInterface(); |
| // More work would need to be done in order to have multiple RenderEngine instances. In |
| // particular, they would not be able to share the same VulkanInterface(s). |
| LOG_ALWAYS_FATAL_IF(!sVulkanInterface.takeOwnership(), |
| "SkiaVkRenderEngine couldn't take ownership of existing unprotected " |
| "VulkanInterface! Only one SkiaVkRenderEngine instance may exist at a " |
| "time."); |
| if (sProtectedContentVulkanInterface.isInitialized()) { |
| // takeOwnership fails on an uninitialized VulkanInterface, but protected content support is |
| // optional. |
| LOG_ALWAYS_FATAL_IF(!sProtectedContentVulkanInterface.takeOwnership(), |
| "SkiaVkRenderEngine couldn't take ownership of existing protected " |
| "VulkanInterface! Only one SkiaVkRenderEngine instance may exist at a " |
| "time."); |
| } |
| |
| SkiaRenderEngine::Contexts contexts; |
| contexts.first = createContext(sVulkanInterface); |
| if (supportsProtectedContentImpl()) { |
| contexts.second = createContext(sProtectedContentVulkanInterface); |
| } |
| |
| return contexts; |
| } |
| |
| bool SkiaVkRenderEngine::supportsProtectedContentImpl() const { |
| return sProtectedContentVulkanInterface.isInitialized(); |
| } |
| |
| bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) { |
| return true; |
| } |
| |
| VulkanInterface& SkiaVkRenderEngine::getVulkanInterface(bool protectedContext) { |
| if (protectedContext) { |
| return sProtectedContentVulkanInterface; |
| } |
| return sVulkanInterface; |
| } |
| |
| int SkiaVkRenderEngine::getContextPriority() { |
| // EGL_CONTEXT_PRIORITY_REALTIME_NV |
| constexpr int kRealtimePriority = 0x3357; |
| if (getVulkanInterface(isProtected()).isRealtimePriority()) { |
| return kRealtimePriority; |
| } else { |
| return 0; |
| } |
| } |
| |
| void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) { |
| StringAppendF(&result, "\n ------------RE Vulkan----------\n"); |
| StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.isInitialized()); |
| StringAppendF(&result, "\n Vulkan protected device initialized: %d\n", |
| sProtectedContentVulkanInterface.isInitialized()); |
| |
| if (!sVulkanInterface.isInitialized()) { |
| return; |
| } |
| |
| StringAppendF(&result, "\n Instance extensions:\n"); |
| for (const auto& name : sVulkanInterface.getInstanceExtensionNames()) { |
| StringAppendF(&result, "\n %s\n", name.c_str()); |
| } |
| |
| StringAppendF(&result, "\n Device extensions:\n"); |
| for (const auto& name : sVulkanInterface.getDeviceExtensionNames()) { |
| StringAppendF(&result, "\n %s\n", name.c_str()); |
| } |
| } |
| |
| } // namespace skia |
| } // namespace renderengine |
| } // namespace android |