Flutter Engine
 
Loading...
Searching...
No Matches
manager.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 <vector>
8
11
12namespace flutter {
13namespace egl {
14
15int Manager::instance_count_ = 0;
16
17std::unique_ptr<Manager> Manager::Create(GpuPreference gpu_preference) {
18 std::unique_ptr<Manager> manager;
19 manager.reset(new Manager(gpu_preference));
20 if (!manager->IsValid()) {
21 return nullptr;
22 }
23 return std::move(manager);
24}
25
26Manager::Manager(GpuPreference gpu_preference) {
27 ++instance_count_;
28
29 if (!InitializeDisplay(gpu_preference)) {
30 return;
31 }
32
33 if (!InitializeConfig()) {
34 return;
35 }
36
37 if (!InitializeContexts()) {
38 return;
39 }
40
41 is_valid_ = true;
42}
43
44Manager::~Manager() {
45 CleanUp();
46 --instance_count_;
47}
48
49bool Manager::InitializeDisplay(GpuPreference gpu_preference) {
50 // If the request for a low power GPU is provided,
51 // we will attempt to select GPU explicitly, via ANGLE extension
52 // that allows to specify the GPU to use via LUID.
53 std::optional<LUID> luid = std::nullopt;
54 if (gpu_preference == GpuPreference::LowPowerPreference) {
55 luid = GetLowPowerGpuLuid();
56 }
57
58 // These are preferred display attributes and request ANGLE's D3D11
59 // renderer (use only in case of valid LUID returned from above).
60 const EGLint d3d11_display_attributes_with_luid[] = {
61 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
62 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
63
64 // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will
65 // enable ANGLE to automatically call the IDXGIDevice3::Trim method on
66 // behalf of the application when it gets suspended.
67 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
68 EGL_TRUE,
69
70 // This extension allows angle to render directly on a D3D swapchain
71 // in the correct orientation on D3D11.
72 EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
73 EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
74
75 // Specify the LUID of the GPU to use.
76 EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE,
77 static_cast<EGLint>(luid.has_value() ? luid->HighPart : 0),
78 EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE,
79 static_cast<EGLint>(luid.has_value() ? luid->LowPart : 0),
80 EGL_NONE,
81 };
82
83 // These are preferred display attributes and request ANGLE's D3D11
84 // renderer. eglInitialize will only succeed with these attributes if the
85 // hardware supports D3D11 Feature Level 10_0+.
86 const EGLint d3d11_display_attributes[] = {
87 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
88 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
89
90 // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will
91 // enable ANGLE to automatically call the IDXGIDevice3::Trim method on
92 // behalf of the application when it gets suspended.
93 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
94 EGL_TRUE,
95
96 // This extension allows angle to render directly on a D3D swapchain
97 // in the correct orientation on D3D11.
98 EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
99 EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
100
101 EGL_NONE,
102 };
103
104 // These are used to request ANGLE's D3D11 renderer, with D3D11 Feature
105 // Level 9_3.
106 const EGLint d3d11_fl_9_3_display_attributes[] = {
107 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
108 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
109 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
110 9,
111 EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
112 3,
113 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
114 EGL_TRUE,
115 EGL_NONE,
116 };
117
118 // These attributes request D3D11 WARP (software rendering fallback) in case
119 // hardware-backed D3D11 is unavailable.
120 const EGLint d3d11_warp_display_attributes[] = {
121 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
122 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
123 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
124 EGL_TRUE,
125 EGL_NONE,
126 };
127
128 std::vector<const EGLint*> display_attributes_configs;
129
130 if (luid) {
131 // If LUID value is present, obtain an adapter with that luid.
132 display_attributes_configs.push_back(d3d11_display_attributes_with_luid);
133 }
134 display_attributes_configs.push_back(d3d11_display_attributes);
135 display_attributes_configs.push_back(d3d11_fl_9_3_display_attributes);
136 display_attributes_configs.push_back(d3d11_warp_display_attributes);
137
138 PFNEGLGETPLATFORMDISPLAYEXTPROC egl_get_platform_display_EXT =
139 reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
140 ::eglGetProcAddress("eglGetPlatformDisplayEXT"));
141 if (!egl_get_platform_display_EXT) {
142 LogEGLError("eglGetPlatformDisplayEXT not available");
143 return false;
144 }
145
146 // Attempt to initialize ANGLE's renderer in order of: D3D11, D3D11 Feature
147 // Level 9_3 and finally D3D11 WARP.
148 for (auto config : display_attributes_configs) {
149 bool is_last = (config == display_attributes_configs.back());
150
151 display_ = egl_get_platform_display_EXT(EGL_PLATFORM_ANGLE_ANGLE,
152 EGL_DEFAULT_DISPLAY, config);
153
154 if (display_ == EGL_NO_DISPLAY) {
155 if (is_last) {
156 LogEGLError("Failed to get a compatible EGLdisplay");
157 return false;
158 }
159
160 // Try the next config.
161 continue;
162 }
163
164 if (::eglInitialize(display_, nullptr, nullptr) == EGL_FALSE) {
165 if (is_last) {
166 LogEGLError("Failed to initialize EGL via ANGLE");
167 return false;
168 }
169
170 // Try the next config.
171 continue;
172 }
173
174 return true;
175 }
176
178}
179
180bool Manager::InitializeConfig() {
181 const EGLint config_attributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
182 EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
183 EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
184 EGL_NONE};
185
186 EGLint num_config = 0;
187
188 EGLBoolean result =
189 ::eglChooseConfig(display_, config_attributes, &config_, 1, &num_config);
190
191 if (result == EGL_TRUE && num_config > 0) {
192 return true;
193 }
194
195 LogEGLError("Failed to choose EGL config");
196 return false;
197}
198
199bool Manager::InitializeContexts() {
200 const EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
201
202 auto const render_context =
203 ::eglCreateContext(display_, config_, EGL_NO_CONTEXT, context_attributes);
204 if (render_context == EGL_NO_CONTEXT) {
205 LogEGLError("Failed to create EGL render context");
206 return false;
207 }
208
209 auto const resource_context =
210 ::eglCreateContext(display_, config_, render_context, context_attributes);
211 if (resource_context == EGL_NO_CONTEXT) {
212 LogEGLError("Failed to create EGL resource context");
213 return false;
214 }
215
216 render_context_ = std::make_unique<Context>(display_, render_context);
217 resource_context_ = std::make_unique<Context>(display_, resource_context);
218 return true;
219}
220
221bool Manager::InitializeDevice() {
222 const auto query_display_attrib_EXT =
223 reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
224 ::eglGetProcAddress("eglQueryDisplayAttribEXT"));
225 const auto query_device_attrib_EXT =
226 reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
227 ::eglGetProcAddress("eglQueryDeviceAttribEXT"));
228
229 if (query_display_attrib_EXT == nullptr ||
230 query_device_attrib_EXT == nullptr) {
231 return false;
232 }
233
234 EGLAttrib egl_device = 0;
235 EGLAttrib angle_device = 0;
236
237 auto result = query_display_attrib_EXT(display_, EGL_DEVICE_EXT, &egl_device);
238 if (result != EGL_TRUE) {
239 return false;
240 }
241
242 result = query_device_attrib_EXT(reinterpret_cast<EGLDeviceEXT>(egl_device),
243 EGL_D3D11_DEVICE_ANGLE, &angle_device);
244 if (result != EGL_TRUE) {
245 return false;
246 }
247
248 resolved_device_ = reinterpret_cast<ID3D11Device*>(angle_device);
249 return true;
250}
251
252void Manager::CleanUp() {
253 EGLBoolean result = EGL_FALSE;
254
255 // Needs to be reset before destroying the contexts.
256 resolved_device_.Reset();
257
258 // Needs to be reset before destroying the EGLDisplay.
259 render_context_.reset();
260 resource_context_.reset();
261
262 if (display_ != EGL_NO_DISPLAY) {
263 // Display is reused between instances so only terminate display
264 // if destroying last instance
265 if (instance_count_ == 1) {
266 ::eglTerminate(display_);
267 }
268 display_ = EGL_NO_DISPLAY;
269 }
270}
271
272bool Manager::IsValid() const {
273 return is_valid_;
274}
275
276std::unique_ptr<WindowSurface> Manager::CreateWindowSurface(HWND hwnd,
277 size_t width,
278 size_t height) {
279 if (!hwnd || !is_valid_) {
280 return nullptr;
281 }
282
283 // Disable ANGLE's automatic surface resizing and provide an explicit size.
284 // The surface will need to be destroyed and re-created if the HWND is
285 // resized.
286 const EGLint surface_attributes[] = {EGL_FIXED_SIZE_ANGLE,
287 EGL_TRUE,
288 EGL_WIDTH,
289 static_cast<EGLint>(width),
290 EGL_HEIGHT,
291 static_cast<EGLint>(height),
292 EGL_NONE};
293
294 auto const surface = ::eglCreateWindowSurface(
295 display_, config_, static_cast<EGLNativeWindowType>(hwnd),
296 surface_attributes);
297 if (surface == EGL_NO_SURFACE) {
298 LogEGLError("Surface creation failed.");
299 return nullptr;
300 }
301
302 return std::make_unique<WindowSurface>(display_, render_context_->GetHandle(),
304}
305
306bool Manager::HasContextCurrent() {
307 return ::eglGetCurrentContext() != EGL_NO_CONTEXT;
308}
309
310EGLSurface Manager::CreateSurfaceFromHandle(EGLenum handle_type,
311 EGLClientBuffer handle,
312 const EGLint* attributes) const {
313 return ::eglCreatePbufferFromClientBuffer(display_, handle_type, handle,
314 config_, attributes);
315}
316
317bool Manager::GetDevice(ID3D11Device** device) {
318 if (!resolved_device_) {
319 if (!InitializeDevice()) {
320 return false;
321 }
322 }
323
324 resolved_device_.CopyTo(device);
325 return (resolved_device_ != nullptr);
326}
327
328Context* Manager::render_context() const {
329 return render_context_.get();
330}
331
332Context* Manager::resource_context() const {
333 return resource_context_.get();
334}
335
336std::optional<LUID> Manager::GetLowPowerGpuLuid() {
337 Microsoft::WRL::ComPtr<IDXGIFactory1> factory1 = nullptr;
338 Microsoft::WRL::ComPtr<IDXGIFactory6> factory6 = nullptr;
339 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter = nullptr;
340 HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&factory1));
341 if (FAILED(hr)) {
342 return std::nullopt;
343 }
344 hr = factory1->QueryInterface(IID_PPV_ARGS(&factory6));
345 if (FAILED(hr)) {
346 // No support for IDXGIFactory6, so we will not use the selected GPU.
347 // We will follow with the default ANGLE selection.
348 return std::nullopt;
349 }
350 hr = factory6->EnumAdapterByGpuPreference(
351 0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, IID_PPV_ARGS(&adapter));
352 if (FAILED(hr) || adapter == nullptr) {
353 return std::nullopt;
354 }
355 // Get the LUID of the adapter.
356 DXGI_ADAPTER_DESC desc;
357 hr = adapter->GetDesc(&desc);
358 if (FAILED(hr)) {
359 return std::nullopt;
360 }
361 return std::make_optional(desc.AdapterLuid);
362}
363
364} // namespace egl
365} // namespace flutter
virtual Context * resource_context() const
Definition manager.cc:332
static std::optional< LUID > GetLowPowerGpuLuid()
Definition manager.cc:336
virtual Context * render_context() const
Definition manager.cc:328
VkDevice device
Definition main.cc:69
VkSurfaceKHR surface
Definition main.cc:65
#define FML_UNREACHABLE()
Definition logging.h:128
void LogEGLError(std::string_view message)
Log the last EGL error with an error message.
Definition egl.cc:55
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
int32_t height
int32_t width
#define FAILED(hr)