| Flutter Impeller |

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
5 #include "impeller/playground/backend/vulkan/playground_impl_vk.h"
6
7 #include "flutter/fml/paths.h"
8 #include "impeller/renderer/backend/vulkan/vk.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"
20 #include "impeller/renderer/backend/vulkan/context_vk.h"
21 #include "impeller/renderer/backend/vulkan/formats_vk.h"
22 #include "impeller/renderer/backend/vulkan/surface_context_vk.h"
23 #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h"
24 #include "impeller/renderer/backend/vulkan/texture_vk.h"
25 #include "impeller/renderer/vk/compute_shaders_vk.h"
26 #include "impeller/scene/shaders/vk/scene_shaders_vk.h"
27
28 namespace impeller {
29
30 static std::vector<std::shared_ptr<fml::Mapping>>
31 ShaderLibraryMappingsForPlayground() {
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
52 vk::UniqueInstance PlaygroundImplVK::global_instance_;
53
54 void PlaygroundImplVK::DestroyWindowHandle(WindowHandle handle) {
55 if (!handle) {
56 return;
57 }
58 ::glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(handle));
59 }
60
61 PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches)
62 : PlaygroundImpl(switches), handle_(nullptr, &DestroyWindowHandle) {
63 FML_CHECK(IsVulkanDriverPresent());
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);
88 context_settings.shader_libraries_data = ShaderLibraryMappingsForPlayground();
89 context_settings.cache_directory = fml::paths::GetCachesDirectory();
90 context_settings.enable_validation = switches_.enable_vulkan_validation;
91
92 auto context_vk = ContextVK::Create(std::move(context_settings));
93 if (!context_vk || !context_vk->IsValid()) {
94 VALIDATION_LOG << "Could not create Vulkan context in the playground.";
95 return;
96 }
97
98 VkSurfaceKHR vk_surface;
99 auto res = vk::Result{::glfwCreateWindowSurface(
100 context_vk->GetInstance(), // instance
101 window, // window
102 nullptr, // allocator
103 &vk_surface // surface
104 )};
105 if (res != vk::Result::eSuccess) {
106 VALIDATION_LOG << "Could not create surface for GLFW window: "
107 << vk::to_string(res);
108 return;
109 }
110
111 vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()};
112 auto context = context_vk->CreateSurfaceContext();
113 if (!context->SetWindowSurface(std::move(surface), size_)) {
114 VALIDATION_LOG << "Could not set up surface for context.";
115 return;
116 }
117
118 context_ = std::move(context);
119 }
120
121 PlaygroundImplVK::~PlaygroundImplVK() = default;
122
123 // |PlaygroundImpl|
124 std::shared_ptr<Context> PlaygroundImplVK::GetContext() const {
125 return context_;
126 }
127
128 // |PlaygroundImpl|
129 PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const {
130 return handle_.get();
131 }
132
133 // |PlaygroundImpl|
134 std::unique_ptr<Surface> PlaygroundImplVK::AcquireSurfaceFrame(
135 std::shared_ptr<Context> context) {
136 SurfaceContextVK* surface_context_vk =
137 reinterpret_cast<SurfaceContextVK*>(context_.get());
138
139 int width = 0;
140 int height = 0;
141 ::glfwGetFramebufferSize(reinterpret_cast<GLFWwindow*>(handle_.get()), &width,
142 &height);
143 size_ = ISize{width, height};
144 surface_context_vk->UpdateSurfaceSize(ISize{width, height});
145
146 return surface_context_vk->AcquireNextSurface();
147 }
148
149 // Create a global instance of Vulkan in order to prevent unloading of the
150 // Vulkan library.
151 // A test suite may repeatedly create and destroy PlaygroundImplVK instances,
152 // and if the PlaygroundImplVK's Vulkan instance is the only one in the
153 // process then the Vulkan library will be unloaded when the instance is
154 // destroyed. Repeated loading and unloading of SwiftShader was leaking
155 // resources, so this will work around that leak.
156 // (see https://github.com/flutter/flutter/issues/138028)
157 void PlaygroundImplVK::InitGlobalVulkanInstance() {
158 if (global_instance_) {
159 return;
160 }
161
162 VULKAN_HPP_DEFAULT_DISPATCHER.init(::glfwGetInstanceProcAddress);
163
164 vk::ApplicationInfo application_info;
165 application_info.setApplicationVersion(VK_API_VERSION_1_0);
166 application_info.setApiVersion(VK_API_VERSION_1_1);
167 application_info.setEngineVersion(VK_API_VERSION_1_0);
168 application_info.setPEngineName("PlaygroundImplVK");
169 application_info.setPApplicationName("PlaygroundImplVK");
170
171 auto caps = std::shared_ptr<CapabilitiesVK>(
172 new CapabilitiesVK(/*enable_validations=*/true));
173 FML_DCHECK(caps->IsValid());
174
175 std::optional<std::vector<std::string>> enabled_layers =
176 caps->GetEnabledLayers();
177 std::optional<std::vector<std::string>> enabled_extensions =
178 caps->GetEnabledInstanceExtensions();
179 FML_DCHECK(enabled_layers.has_value() && enabled_extensions.has_value());
180
181 std::vector<const char*> enabled_layers_c;
182 std::vector<const char*> enabled_extensions_c;
183
184 if (enabled_layers.has_value()) {
185 for (const auto& layer : enabled_layers.value()) {
186 enabled_layers_c.push_back(layer.c_str());
187 }
188 }
189
190 if (enabled_extensions.has_value()) {
191 for (const auto& ext : enabled_extensions.value()) {
192 enabled_extensions_c.push_back(ext.c_str());
193 }
194 }
195
196 vk::InstanceCreateFlags instance_flags = {};
197 instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
198 vk::InstanceCreateInfo instance_info;
199 instance_info.setPEnabledLayerNames(enabled_layers_c);
200 instance_info.setPEnabledExtensionNames(enabled_extensions_c);
201 instance_info.setPApplicationInfo(&application_info);
202 instance_info.setFlags(instance_flags);
203 auto instance_result = vk::createInstanceUnique(instance_info);
204 FML_CHECK(instance_result.result == vk::Result::eSuccess)
205 << "Unable to initialize global Vulkan instance";
206 global_instance_ = std::move(instance_result.value);
207 }
208
209 fml::Status PlaygroundImplVK::SetCapabilities(
210 const std::shared_ptr<Capabilities>& capabilities) {
211 return fml::Status(
212 fml::StatusCode::kUnimplemented,
213 "PlaygroundImplVK doesn't support setting the capabilities.");
214 }
215
216 bool PlaygroundImplVK::IsVulkanDriverPresent() {
217 if (::glfwVulkanSupported()) {
218 return true;
219 }
220 #ifdef TARGET_OS_MAC
221 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on macOS "
222 "where Vulkan cannot be found. It can be installed via "
223 "MoltenVK and make sure to install it globally so "
224 "dlopen can find it.";
225 #else // TARGET_OS_MAC
226 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on a system "
227 "that does not support Vulkan.";
228 #endif // TARGET_OS_MAC
229 return false;
230 }
231
232 } // namespace impeller
impeller::PlaygroundImplVK::IsVulkanDriverPresent
static bool IsVulkanDriverPresent()
Definition: playground_impl_vk.cc:216
khr_surface_vk.h
impeller::ContextVK::Settings::enable_validation
bool enable_validation
Definition: context_vk.h:50
surface_context_vk.h
formats_vk.h
impeller::PlaygroundImpl
Definition: playground_impl.h:18
vk.h
impeller::ContextVK::Settings
Definition: context_vk.h:46
impeller::TSize< int64_t >
impeller::ContextVK::Settings::proc_address_callback
PFN_vkGetInstanceProcAddr proc_address_callback
Definition: context_vk.h:47
impeller::ContextVK::Settings::shader_libraries_data
std::vector< std::shared_ptr< fml::Mapping > > shader_libraries_data
Definition: context_vk.h:48
impeller::ShaderLibraryMappingsForPlayground
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
Definition: playground_impl_gles.cc:106
impeller::PlaygroundImplVK::PlaygroundImplVK
PlaygroundImplVK(PlaygroundSwitches switches)
Definition: playground_impl_vk.cc:61
impeller::ContextVK::Create
static std::shared_ptr< ContextVK > Create(Settings settings)
Definition: context_vk.cc:100
texture_vk.h
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
impeller::PlaygroundImpl::switches_
const PlaygroundSwitches switches_
Definition: playground_impl.h:40
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::PlaygroundImplVK::SetCapabilities
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
Definition: playground_impl_vk.cc:209
playground_impl_vk.h
impeller::ContextVK::Settings::cache_directory
fml::UniqueFD cache_directory
Definition: context_vk.h:49
impeller::PlaygroundSwitches
Definition: switches.h:16
impeller::PlaygroundSwitches::enable_vulkan_validation
bool enable_vulkan_validation
Definition: switches.h:22
impeller::PlaygroundImplVK::~PlaygroundImplVK
~PlaygroundImplVK()
context_vk.h
impeller
Definition: aiks_blur_unittests.cc:20
impeller::PlaygroundImpl::WindowHandle
void * WindowHandle
Definition: playground_impl.h:25