blob: bd501073d74b49c99445fb971ed07e8325e5384c [file] [log] [blame]
/*
* 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/GrVkExtensions.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