blob: a10fa4790ec65ccb8f1eaf45cee761e9e8a56d46 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/common/shell_test_platform_view_vulkan.h"
#include <utility>
#include "flutter/common/graphics/persistent_cache.h"
#include "flutter/flutter_vma/flutter_skia_vma.h"
#include "flutter/shell/common/context_options.h"
#include "flutter/vulkan/vulkan_skia_proc_table.h"
#include "flutter/vulkan/vulkan_utilities.h"
#include "third_party/skia/include/core/SkSurface.h"
#if OS_FUCHSIA
#define VULKAN_SO_PATH "libvulkan.so"
#elif FML_OS_MACOSX
#define VULKAN_SO_PATH "libvk_swiftshader.dylib"
#elif FML_OS_WIN
#define VULKAN_SO_PATH "vk_swiftshader.dll"
#else
#define VULKAN_SO_PATH "libvk_swiftshader.so"
#endif
namespace flutter {
namespace testing {
ShellTestPlatformViewVulkan::ShellTestPlatformViewVulkan(
PlatformView::Delegate& delegate,
const TaskRunners& task_runners,
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
CreateVsyncWaiter create_vsync_waiter,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder)
: ShellTestPlatformView(delegate, task_runners),
create_vsync_waiter_(std::move(create_vsync_waiter)),
vsync_clock_(std::move(vsync_clock)),
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>(VULKAN_SO_PATH)),
shell_test_external_view_embedder_(
std::move(shell_test_external_view_embedder)) {}
ShellTestPlatformViewVulkan::~ShellTestPlatformViewVulkan() = default;
std::unique_ptr<VsyncWaiter> ShellTestPlatformViewVulkan::CreateVSyncWaiter() {
return create_vsync_waiter_();
}
void ShellTestPlatformViewVulkan::SimulateVSync() {
vsync_clock_->SimulateVSync();
}
// |PlatformView|
std::unique_ptr<Surface> ShellTestPlatformViewVulkan::CreateRenderingSurface() {
return std::make_unique<OffScreenSurface>(proc_table_,
shell_test_external_view_embedder_);
}
// |PlatformView|
std::shared_ptr<ExternalViewEmbedder>
ShellTestPlatformViewVulkan::CreateExternalViewEmbedder() {
return shell_test_external_view_embedder_;
}
// |PlatformView|
PointerDataDispatcherMaker ShellTestPlatformViewVulkan::GetDispatcherMaker() {
return [](DefaultPointerDataDispatcher::Delegate& delegate) {
return std::make_unique<SmoothPointerDataDispatcher>(delegate);
};
}
// TODO(gw280): This code was forked from vulkan_window.cc specifically for
// shell_test.
// We need to merge this functionality back into //vulkan.
// https://github.com/flutter/flutter/issues/51132
ShellTestPlatformViewVulkan::OffScreenSurface::OffScreenSurface(
fml::RefPtr<vulkan::VulkanProcTable> vk,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder)
: valid_(false),
vk_(std::move(vk)),
shell_test_external_view_embedder_(
std::move(shell_test_external_view_embedder)) {
if (!vk_ || !vk_->HasAcquiredMandatoryProcAddresses()) {
FML_DLOG(ERROR) << "Proc table has not acquired mandatory proc addresses.";
return;
}
// Create the application instance.
std::vector<std::string> extensions = {
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
};
application_ = std::make_unique<vulkan::VulkanApplication>(
*vk_, "FlutterTest", std::move(extensions), VK_MAKE_VERSION(1, 0, 0),
VK_MAKE_VERSION(1, 1, 0), true);
if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
// Make certain the application instance was created and it set up the
// instance proc table entries.
FML_DLOG(ERROR) << "Instance proc addresses have not been set up.";
return;
}
// Create the device.
logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
if (logical_device_ == nullptr || !logical_device_->IsValid() ||
!vk_->AreDeviceProcsSetup()) {
// Make certain the device was created and it set up the device proc table
// entries.
FML_DLOG(ERROR) << "Device proc addresses have not been set up.";
return;
}
memory_allocator_ = FlutterSkiaVulkanMemoryAllocator::Make(
application_->GetAPIVersion(), application_->GetInstance(),
logical_device_->GetPhysicalDeviceHandle(), logical_device_->GetHandle(),
vk_, true);
// Create the Skia GrContext.
if (!CreateSkiaGrContext()) {
FML_DLOG(ERROR) << "Could not create Skia context.";
return;
}
valid_ = true;
}
bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaGrContext() {
GrVkBackendContext backend_context;
if (!CreateSkiaBackendContext(&backend_context)) {
FML_DLOG(ERROR) << "Could not create Skia backend context.";
return false;
}
const auto options =
MakeDefaultContextOptions(ContextType::kRender, GrBackendApi::kVulkan);
sk_sp<GrDirectContext> context =
GrDirectContext::MakeVulkan(backend_context, options);
if (context == nullptr) {
FML_DLOG(ERROR) << "Failed to create GrDirectContext";
return false;
}
context->setResourceCacheLimit(vulkan::kGrCacheMaxByteSize);
context_ = context;
return true;
}
bool ShellTestPlatformViewVulkan::OffScreenSurface::CreateSkiaBackendContext(
GrVkBackendContext* context) {
auto getProc = CreateSkiaGetProc(vk_);
if (getProc == nullptr) {
FML_DLOG(ERROR) << "GetProcAddress is null";
return false;
}
uint32_t skia_features = 0;
if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
FML_DLOG(ERROR) << "Failed to get Physical Device features";
return false;
}
context->fInstance = application_->GetInstance();
context->fPhysicalDevice = logical_device_->GetPhysicalDeviceHandle();
context->fDevice = logical_device_->GetHandle();
context->fQueue = logical_device_->GetQueueHandle();
context->fGraphicsQueueIndex = logical_device_->GetGraphicsQueueIndex();
context->fMinAPIVersion = application_->GetAPIVersion();
context->fMaxAPIVersion = application_->GetAPIVersion();
context->fFeatures = skia_features;
context->fGetProc = std::move(getProc);
context->fOwnsInstanceAndDevice = false;
context->fMemoryAllocator = memory_allocator_;
return true;
}
ShellTestPlatformViewVulkan::OffScreenSurface::~OffScreenSurface() {}
bool ShellTestPlatformViewVulkan::OffScreenSurface::IsValid() {
return valid_;
}
std::unique_ptr<SurfaceFrame>
ShellTestPlatformViewVulkan::OffScreenSurface::AcquireFrame(
const SkISize& size) {
auto image_info = SkImageInfo::Make(size, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kOpaque_SkAlphaType);
auto surface = SkSurface::MakeRenderTarget(
context_.get(), skgpu::Budgeted::kNo, image_info, 0, nullptr);
SurfaceFrame::SubmitCallback callback = [](const SurfaceFrame&,
SkCanvas* canvas) -> bool {
canvas->flush();
return true;
};
SurfaceFrame::FramebufferInfo framebuffer_info;
framebuffer_info.supports_readback = true;
return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info,
std::move(callback),
/*frame_size=*/SkISize::Make(800, 600));
}
GrDirectContext* ShellTestPlatformViewVulkan::OffScreenSurface::GetContext() {
return context_.get();
}
SkMatrix ShellTestPlatformViewVulkan::OffScreenSurface::GetRootTransformation()
const {
SkMatrix matrix;
matrix.reset();
return matrix;
}
} // namespace testing
} // namespace flutter