Flutter Engine
The Flutter Engine
playground_impl_vk.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include "flutter/fml/paths.h"
9
10#define GLFW_INCLUDE_VULKAN
11#include <GLFW/glfw3.h>
12
13#include "flutter/fml/logging.h"
14#include "flutter/fml/mapping.h"
15#include "impeller/entity/vk/entity_shaders_vk.h"
16#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h"
17#include "impeller/entity/vk/modern_shaders_vk.h"
18#include "impeller/fixtures/vk/fixtures_shaders_vk.h"
19#include "impeller/playground/imgui/vk/imgui_shaders_vk.h"
25#include "impeller/renderer/vk/compute_shaders_vk.h"
26#include "impeller/scene/shaders/vk/scene_shaders_vk.h"
27
28namespace impeller {
29
30static std::vector<std::shared_ptr<fml::Mapping>>
32 return {
33 std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
34 impeller_entity_shaders_vk_length),
35 std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
36 impeller_modern_shaders_vk_length),
37 std::make_shared<fml::NonOwnedMapping>(
38 impeller_framebuffer_blend_shaders_vk_data,
39 impeller_framebuffer_blend_shaders_vk_length),
40 std::make_shared<fml::NonOwnedMapping>(
41 impeller_fixtures_shaders_vk_data,
42 impeller_fixtures_shaders_vk_length),
43 std::make_shared<fml::NonOwnedMapping>(impeller_imgui_shaders_vk_data,
44 impeller_imgui_shaders_vk_length),
45 std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_vk_data,
46 impeller_scene_shaders_vk_length),
47 std::make_shared<fml::NonOwnedMapping>(
48 impeller_compute_shaders_vk_data, impeller_compute_shaders_vk_length),
49 };
50}
51
52vk::UniqueInstance PlaygroundImplVK::global_instance_;
53
54void PlaygroundImplVK::DestroyWindowHandle(WindowHandle handle) {
55 if (!handle) {
56 return;
57 }
58 ::glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(handle));
59}
60
62 : PlaygroundImpl(switches), handle_(nullptr, &DestroyWindowHandle) {
64
65 InitGlobalVulkanInstance();
66
67 ::glfwDefaultWindowHints();
68 ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
69 ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
70
71 auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
72 if (!window) {
73 VALIDATION_LOG << "Unable to create glfw window";
74 return;
75 }
76
77 int width = 0;
78 int height = 0;
79 ::glfwGetWindowSize(window, &width, &height);
80 size_ = ISize{width, height};
81
82 handle_.reset(window);
83
84 ContextVK::Settings context_settings;
85 context_settings.proc_address_callback =
86 reinterpret_cast<PFN_vkGetInstanceProcAddr>(
87 &::glfwGetInstanceProcAddress);
91 context_settings.fatal_missing_validations =
93 ;
94
95 auto context_vk = ContextVK::Create(std::move(context_settings));
96 if (!context_vk || !context_vk->IsValid()) {
97 VALIDATION_LOG << "Could not create Vulkan context in the playground.";
98 return;
99 }
100
101 VkSurfaceKHR vk_surface;
102 auto res = vk::Result{::glfwCreateWindowSurface(
103 context_vk->GetInstance(), // instance
104 window, // window
105 nullptr, // allocator
106 &vk_surface // surface
107 )};
108 if (res != vk::Result::eSuccess) {
109 VALIDATION_LOG << "Could not create surface for GLFW window: "
110 << vk::to_string(res);
111 return;
112 }
113
114 vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()};
115 auto context = context_vk->CreateSurfaceContext();
116 if (!context->SetWindowSurface(std::move(surface), size_)) {
117 VALIDATION_LOG << "Could not set up surface for context.";
118 return;
119 }
120
121 context_ = std::move(context);
122}
123
125
126// |PlaygroundImpl|
127std::shared_ptr<Context> PlaygroundImplVK::GetContext() const {
128 return context_;
129}
130
131// |PlaygroundImpl|
132PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const {
133 return handle_.get();
134}
135
136// |PlaygroundImpl|
137std::unique_ptr<Surface> PlaygroundImplVK::AcquireSurfaceFrame(
138 std::shared_ptr<Context> context) {
139 SurfaceContextVK* surface_context_vk =
140 reinterpret_cast<SurfaceContextVK*>(context_.get());
141
142 int width = 0;
143 int height = 0;
144 ::glfwGetFramebufferSize(reinterpret_cast<GLFWwindow*>(handle_.get()), &width,
145 &height);
146 size_ = ISize{width, height};
147 surface_context_vk->UpdateSurfaceSize(ISize{width, height});
148
149 return surface_context_vk->AcquireNextSurface();
150}
151
152// Create a global instance of Vulkan in order to prevent unloading of the
153// Vulkan library.
154// A test suite may repeatedly create and destroy PlaygroundImplVK instances,
155// and if the PlaygroundImplVK's Vulkan instance is the only one in the
156// process then the Vulkan library will be unloaded when the instance is
157// destroyed. Repeated loading and unloading of SwiftShader was leaking
158// resources, so this will work around that leak.
159// (see https://github.com/flutter/flutter/issues/138028)
160void PlaygroundImplVK::InitGlobalVulkanInstance() {
161 if (global_instance_) {
162 return;
163 }
164
165 VULKAN_HPP_DEFAULT_DISPATCHER.init(::glfwGetInstanceProcAddress);
166
167 vk::ApplicationInfo application_info;
168 application_info.setApplicationVersion(VK_API_VERSION_1_0);
169 application_info.setApiVersion(VK_API_VERSION_1_1);
170 application_info.setEngineVersion(VK_API_VERSION_1_0);
171 application_info.setPEngineName("PlaygroundImplVK");
172 application_info.setPApplicationName("PlaygroundImplVK");
173
174 auto caps = std::shared_ptr<CapabilitiesVK>(
175 new CapabilitiesVK(/*enable_validations=*/true));
176 FML_DCHECK(caps->IsValid());
177
178 std::optional<std::vector<std::string>> enabled_layers =
179 caps->GetEnabledLayers();
180 std::optional<std::vector<std::string>> enabled_extensions =
181 caps->GetEnabledInstanceExtensions();
182 FML_DCHECK(enabled_layers.has_value() && enabled_extensions.has_value());
183
184 std::vector<const char*> enabled_layers_c;
185 std::vector<const char*> enabled_extensions_c;
186
187 if (enabled_layers.has_value()) {
188 for (const auto& layer : enabled_layers.value()) {
189 enabled_layers_c.push_back(layer.c_str());
190 }
191 }
192
193 if (enabled_extensions.has_value()) {
194 for (const auto& ext : enabled_extensions.value()) {
195 enabled_extensions_c.push_back(ext.c_str());
196 }
197 }
198
199 vk::InstanceCreateFlags instance_flags = {};
200 instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
201 vk::InstanceCreateInfo instance_info;
202 instance_info.setPEnabledLayerNames(enabled_layers_c);
203 instance_info.setPEnabledExtensionNames(enabled_extensions_c);
204 instance_info.setPApplicationInfo(&application_info);
205 instance_info.setFlags(instance_flags);
206 auto instance_result = vk::createInstanceUnique(instance_info);
207 FML_CHECK(instance_result.result == vk::Result::eSuccess)
208 << "Unable to initialize global Vulkan instance";
209 global_instance_ = std::move(instance_result.value);
210}
211
213 const std::shared_ptr<Capabilities>& capabilities) {
214 return fml::Status(
216 "PlaygroundImplVK doesn't support setting the capabilities.");
217}
218
220 if (::glfwVulkanSupported()) {
221 return true;
222 }
223#ifdef TARGET_OS_MAC
224 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on macOS "
225 "where Vulkan cannot be found. It can be installed via "
226 "MoltenVK and make sure to install it globally so "
227 "dlopen can find it.";
228#else // TARGET_OS_MAC
229 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on a system "
230 "that does not support Vulkan.";
231#endif // TARGET_OS_MAC
232 return false;
233}
234
235} // namespace impeller
static std::shared_ptr< ContextVK > Create(Settings settings)
Definition: context_vk.cc:100
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
PlaygroundImplVK(PlaygroundSwitches switches)
const PlaygroundSwitches switches_
GLFWwindow * window
Definition: main.cc:45
VkSurfaceKHR surface
Definition: main.cc:49
#define GLFW_FALSE
Definition: flutter_glfw.cc:36
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
fml::UniqueFD GetCachesDirectory()
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
ISize64 ISize
Definition: size.h:140
Task::Status Status
Definition: TaskList.cpp:15
static SkString to_string(int n)
Definition: nanobench.cpp:119
fuchsia::ui::composition::ParentViewportWatcherHandle handle_
int32_t height
int32_t width
std::vector< std::shared_ptr< fml::Mapping > > shader_libraries_data
Definition: context_vk.h:48
PFN_vkGetInstanceProcAddr proc_address_callback
Definition: context_vk.h:47
bool fatal_missing_validations
If validations are requested but cannot be enabled, log a fatal error.
Definition: context_vk.h:53
fml::UniqueFD cache_directory
Definition: context_vk.h:49
#define ERROR(message)
Definition: elf_loader.cc:260
#define VALIDATION_LOG
Definition: validation.h:73
#define VK_API_VERSION_1_0
Definition: vulkan_core.h:69
PFN_vkVoidFunction(VKAPI_PTR * PFN_vkGetInstanceProcAddr)(VkInstance instance, const char *pName)
Definition: vulkan_core.h:3989
#define VK_API_VERSION_1_1
Definition: vulkan_core.h:4921