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