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/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 
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>(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 
62  : PlaygroundImpl(switches), handle_(nullptr, &DestroyWindowHandle) {
63  if (!::glfwVulkanSupported()) {
64 #ifdef TARGET_OS_MAC
65  VALIDATION_LOG << "Attempted to initialize a Vulkan playground on macOS "
66  "where Vulkan cannot be found. It can be installed via "
67  "MoltenVK and make sure to install it globally so "
68  "dlopen can find it.";
69 #else
70  VALIDATION_LOG << "Attempted to initialize a Vulkan playground on a system "
71  "that does not support Vulkan.";
72 #endif
73  return;
74  }
75 
76  InitGlobalVulkanInstance();
77 
78  ::glfwDefaultWindowHints();
79  ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
80  ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
81 
82  auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
83  if (!window) {
84  VALIDATION_LOG << "Unable to create glfw window";
85  return;
86  }
87 
88  handle_.reset(window);
89 
90  ContextVK::Settings context_settings;
91  context_settings.proc_address_callback =
92  reinterpret_cast<PFN_vkGetInstanceProcAddr>(
93  &::glfwGetInstanceProcAddress);
95  context_settings.cache_directory = fml::paths::GetCachesDirectory();
97 
98  auto context_vk = ContextVK::Create(std::move(context_settings));
99  if (!context_vk || !context_vk->IsValid()) {
100  VALIDATION_LOG << "Could not create Vulkan context in the playground.";
101  return;
102  }
103 
104  // Without this, the playground will timeout waiting for the presentation.
105  // It's better to have some Vulkan validation tests running on CI to catch
106  // regressions, but for now this is a workaround.
107  //
108  // TODO(matanlurey): https://github.com/flutter/flutter/issues/134852.
109  //
110  // (Note, if you're using MoltenVK, or Linux, you can comment out this line).
111  context_vk->SetSyncPresentation(true);
112 
113  VkSurfaceKHR vk_surface;
114  auto res = vk::Result{::glfwCreateWindowSurface(
115  context_vk->GetInstance(), // instance
116  window, // window
117  nullptr, // allocator
118  &vk_surface // surface
119  )};
120  if (res != vk::Result::eSuccess) {
121  VALIDATION_LOG << "Could not create surface for GLFW window: "
122  << vk::to_string(res);
123  return;
124  }
125 
126  vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()};
127  auto context = context_vk->CreateSurfaceContext();
128  if (!context->SetWindowSurface(std::move(surface))) {
129  VALIDATION_LOG << "Could not set up surface for context.";
130  return;
131  }
132 
133  context_ = std::move(context);
134 }
135 
137 
138 // |PlaygroundImpl|
139 std::shared_ptr<Context> PlaygroundImplVK::GetContext() const {
140  return context_;
141 }
142 
143 // |PlaygroundImpl|
144 PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const {
145  return handle_.get();
146 }
147 
148 // |PlaygroundImpl|
149 std::unique_ptr<Surface> PlaygroundImplVK::AcquireSurfaceFrame(
150  std::shared_ptr<Context> context) {
151  SurfaceContextVK* surface_context_vk =
152  reinterpret_cast<SurfaceContextVK*>(context_.get());
153  return surface_context_vk->AcquireNextSurface();
154 }
155 
156 // Create a global instance of Vulkan in order to prevent unloading of the
157 // Vulkan library.
158 // A test suite may repeatedly create and destroy PlaygroundImplVK instances,
159 // and if the PlaygroundImplVK's Vulkan instance is the only one in the
160 // process then the Vulkan library will be unloaded when the instance is
161 // destroyed. Repeated loading and unloading of SwiftShader was leaking
162 // resources, so this will work around that leak.
163 // (see https://github.com/flutter/flutter/issues/138028)
164 void PlaygroundImplVK::InitGlobalVulkanInstance() {
165  if (global_instance_) {
166  return;
167  }
168 
169  VULKAN_HPP_DEFAULT_DISPATCHER.init(::glfwGetInstanceProcAddress);
170 
171  vk::ApplicationInfo application_info;
172  application_info.setApplicationVersion(VK_API_VERSION_1_0);
173  application_info.setApiVersion(VK_API_VERSION_1_1);
174  application_info.setEngineVersion(VK_API_VERSION_1_0);
175  application_info.setPEngineName("PlaygroundImplVK");
176  application_info.setPApplicationName("PlaygroundImplVK");
177 
178  auto instance_result =
179  vk::createInstanceUnique(vk::InstanceCreateInfo({}, &application_info));
180  FML_CHECK(instance_result.result == vk::Result::eSuccess)
181  << "Unable to initialize global Vulkan instance";
182  global_instance_ = std::move(instance_result.value);
183 }
184 
186  const std::shared_ptr<Capabilities>& capabilities) {
187  return fml::Status(
188  fml::StatusCode::kUnimplemented,
189  "PlaygroundImplVK doesn't support setting the capabilities.");
190 }
191 
192 } // namespace impeller
impeller::ContextVK::Settings::enable_validation
bool enable_validation
Definition: context_vk.h:48
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:44
impeller::ContextVK::Settings::proc_address_callback
PFN_vkGetInstanceProcAddr proc_address_callback
Definition: context_vk.h:45
impeller::ContextVK::Settings::shader_libraries_data
std::vector< std::shared_ptr< fml::Mapping > > shader_libraries_data
Definition: context_vk.h:46
impeller::ShaderLibraryMappingsForPlayground
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
Definition: playground_impl_gles.cc:91
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:95
texture_vk.h
impeller::PlaygroundImpl::switches_
const PlaygroundSwitches switches_
Definition: playground_impl.h:40
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
impeller::PlaygroundImplVK::SetCapabilities
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
Definition: playground_impl_vk.cc:185
playground_impl_vk.h
impeller::ContextVK::Settings::cache_directory
fml::UniqueFD cache_directory
Definition: context_vk.h:47
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_context.cc:10
impeller::PlaygroundImpl::WindowHandle
void * WindowHandle
Definition: playground_impl.h:25