Flutter Engine
 
Loading...
Searching...
No Matches
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
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>(
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// A global Vulkan instance that is reused across all Vulkan playgrounds.
54// This instance is kept for the entire process lifetime. It is not cleaned
55// up during shutdown to avoid conflicts with destruction of other globals
56// in dependencies like the Vulkan validation layers.
57VkInstance PlaygroundImplVK::global_instance_ = VK_NULL_HANDLE;
58
59void PlaygroundImplVK::DestroyWindowHandle(WindowHandle handle) {
60 if (!handle) {
61 return;
62 }
63 ::glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(handle));
64}
65
67 : PlaygroundImpl(switches), handle_(nullptr, &DestroyWindowHandle) {
69
70 InitGlobalVulkanInstance();
71
72 ::glfwDefaultWindowHints();
73 ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
74 ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
75
76 auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
77 if (!window) {
78 VALIDATION_LOG << "Unable to create glfw window";
79 return;
80 }
81
82 int width = 0;
83 int height = 0;
84 ::glfwGetWindowSize(window, &width, &height);
85 size_ = ISize{width, height};
86
87 handle_.reset(window);
88
89 ContextVK::Settings context_settings;
90 context_settings.proc_address_callback =
91 reinterpret_cast<PFN_vkGetInstanceProcAddr>(
92 &::glfwGetInstanceProcAddress);
96 context_settings.fatal_missing_validations =
98 context_settings.flags = switches_.flags;
99
100 auto context_vk = ContextVK::Create(std::move(context_settings));
101 if (!context_vk || !context_vk->IsValid()) {
102 VALIDATION_LOG << "Could not create Vulkan context in the playground.";
103 return;
104 }
105
106 VkSurfaceKHR vk_surface;
107 auto res = vk::Result{::glfwCreateWindowSurface(
108 context_vk->GetInstance(), // instance
109 window, // window
110 nullptr, // allocator
111 &vk_surface // surface
112 )};
113 if (res != vk::Result::eSuccess) {
114 VALIDATION_LOG << "Could not create surface for GLFW window: "
115 << vk::to_string(res);
116 return;
117 }
118
119 vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()};
120 auto context = context_vk->CreateSurfaceContext();
121 if (!context->SetWindowSurface(std::move(surface), size_)) {
122 VALIDATION_LOG << "Could not set up surface for context.";
123 return;
124 }
125
126 context_ = std::move(context);
127}
128
130
131// |PlaygroundImpl|
132std::shared_ptr<Context> PlaygroundImplVK::GetContext() const {
133 return context_;
134}
135
136// |PlaygroundImpl|
137PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const {
138 return handle_.get();
139}
140
141// |PlaygroundImpl|
142std::unique_ptr<Surface> PlaygroundImplVK::AcquireSurfaceFrame(
143 std::shared_ptr<Context> context) {
144 SurfaceContextVK* surface_context_vk =
145 reinterpret_cast<SurfaceContextVK*>(context_.get());
146
147 int width = 0;
148 int height = 0;
149 ::glfwGetFramebufferSize(reinterpret_cast<GLFWwindow*>(handle_.get()), &width,
150 &height);
151 size_ = ISize{width, height};
152 surface_context_vk->UpdateSurfaceSize(ISize{width, height});
153
154 return surface_context_vk->AcquireNextSurface();
155}
156
157// Create a global instance of Vulkan in order to prevent unloading of the
158// Vulkan library.
159// A test suite may repeatedly create and destroy PlaygroundImplVK instances,
160// and if the PlaygroundImplVK's Vulkan instance is the only one in the
161// process then the Vulkan library will be unloaded when the instance is
162// destroyed. Repeated loading and unloading of SwiftShader was leaking
163// resources, so this will work around that leak.
164// (see https://github.com/flutter/flutter/issues/138028)
165void PlaygroundImplVK::InitGlobalVulkanInstance() {
166 if (global_instance_) {
167 return;
168 }
169
170 VULKAN_HPP_DEFAULT_DISPATCHER.init(::glfwGetInstanceProcAddress);
171
172 vk::ApplicationInfo application_info;
173 application_info.setApplicationVersion(VK_API_VERSION_1_0);
174 application_info.setApiVersion(VK_API_VERSION_1_1);
175 application_info.setEngineVersion(VK_API_VERSION_1_0);
176 application_info.setPEngineName("PlaygroundImplVK");
177 application_info.setPApplicationName("PlaygroundImplVK");
178
179 auto caps = std::shared_ptr<CapabilitiesVK>(
180 new CapabilitiesVK(/*enable_validations=*/true));
181 FML_DCHECK(caps->IsValid());
182
183 std::optional<std::vector<std::string>> enabled_layers =
184 caps->GetEnabledLayers();
185 std::optional<std::vector<std::string>> enabled_extensions =
186 caps->GetEnabledInstanceExtensions();
187 FML_DCHECK(enabled_layers.has_value() && enabled_extensions.has_value());
188
189 std::vector<const char*> enabled_layers_c;
190 std::vector<const char*> enabled_extensions_c;
191
192 if (enabled_layers.has_value()) {
193 for (const auto& layer : enabled_layers.value()) {
194 enabled_layers_c.push_back(layer.c_str());
195 }
196 }
197
198 if (enabled_extensions.has_value()) {
199 for (const auto& ext : enabled_extensions.value()) {
200 enabled_extensions_c.push_back(ext.c_str());
201 }
202 }
203
204 vk::InstanceCreateFlags instance_flags = {};
205 instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
206 vk::InstanceCreateInfo instance_info;
207 instance_info.setPEnabledLayerNames(enabled_layers_c);
208 instance_info.setPEnabledExtensionNames(enabled_extensions_c);
209 instance_info.setPApplicationInfo(&application_info);
210 instance_info.setFlags(instance_flags);
211 auto instance_result = vk::createInstanceUnique(instance_info);
212 FML_CHECK(instance_result.result == vk::Result::eSuccess)
213 << "Unable to initialize global Vulkan instance";
214 global_instance_ = instance_result.value.release();
215}
216
218 const std::shared_ptr<Capabilities>& capabilities) {
219 return fml::Status(
221 "PlaygroundImplVK doesn't support setting the capabilities.");
222}
223
225 if (::glfwVulkanSupported()) {
226 return true;
227 }
228#ifdef TARGET_OS_MAC
229 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on macOS "
230 "where Vulkan cannot be found. It can be installed via "
231 "MoltenVK and make sure to install it globally so "
232 "dlopen can find it.";
233#else // TARGET_OS_MAC
234 FML_LOG(ERROR) << "Attempting to initialize a Vulkan playground on a system "
235 "that does not support Vulkan.";
236#endif // TARGET_OS_MAC
237 return false;
238}
239
240// |PlaygroundImpl|
242PlaygroundImplVK::CreateVKProcAddressResolver() const {
243 return [](void* instance, const char* proc_name) -> void* {
244 return reinterpret_cast<void*>(::glfwGetInstanceProcAddress(
245 reinterpret_cast<VkInstance>(instance), proc_name));
246 };
247}
248
249} // namespace impeller
static std::shared_ptr< ContextVK > Create(Settings settings)
std::function< void *(void *instance, const char *proc_name)> VKProcAddressResolver
Definition playground.h:122
const PlaygroundSwitches switches_
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
PlaygroundImplVK(PlaygroundSwitches switches)
int32_t value
GLFWwindow * window
Definition main.cc:60
VkInstance instance
Definition main.cc:64
VkSurfaceKHR surface
Definition main.cc:65
#define GLFW_FALSE
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
fml::UniqueFD GetCachesDirectory()
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
ISize64 ISize
Definition size.h:162
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:81
PFN_vkGetInstanceProcAddr proc_address_callback
Definition context_vk.h:80
bool fatal_missing_validations
If validations are requested but cannot be enabled, log a fatal error.
Definition context_vk.h:87
#define VALIDATION_LOG
Definition validation.h:91