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