| Flutter Windows Embedder |

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
5 #include "flutter/shell/platform/windows/egl/manager.h"
6
7 #include <vector>
8
9 #include "flutter/fml/logging.h"
10 #include "flutter/shell/platform/windows/egl/egl.h"
11
12 namespace flutter {
13 namespace egl {
14
15 int Manager::instance_count_ = 0;
16
17 std::unique_ptr<Manager> Manager::Create() {
18 std::unique_ptr<Manager> manager;
19 manager.reset(new Manager());
20 if (!manager->IsValid()) {
21 return nullptr;
22 }
23 return std::move(manager);
24 }
25
26 Manager::Manager() {
27 ++instance_count_;
28
29 if (!InitializeDisplay()) {
30 return;
31 }
32
33 if (!InitializeConfig()) {
34 return;
35 }
36
37 if (!InitializeContexts()) {
38 return;
39 }
40
41 is_valid_ = true;
42 }
43
44 Manager::~Manager() {
45 CleanUp();
46 --instance_count_;
47 }
48
49 bool Manager::InitializeDisplay() {
50 // These are preferred display attributes and request ANGLE's D3D11
51 // renderer. eglInitialize will only succeed with these attributes if the
52 // hardware supports D3D11 Feature Level 10_0+.
53 const EGLint d3d11_display_attributes[] = {
54 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
55 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
56
57 // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will
58 // enable ANGLE to automatically call the IDXGIDevice3::Trim method on
59 // behalf of the application when it gets suspended.
60 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
61 EGL_TRUE,
62
63 // This extension allows angle to render directly on a D3D swapchain
64 // in the correct orientation on D3D11.
65 EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
66 EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
67
68 EGL_NONE,
69 };
70
71 // These are used to request ANGLE's D3D11 renderer, with D3D11 Feature
72 // Level 9_3.
73 const EGLint d3d11_fl_9_3_display_attributes[] = {
74 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
75 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
76 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
77 9,
78 EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
79 3,
80 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
81 EGL_TRUE,
82 EGL_NONE,
83 };
84
85 // These attributes request D3D11 WARP (software rendering fallback) in case
86 // hardware-backed D3D11 is unavailable.
87 const EGLint d3d11_warp_display_attributes[] = {
88 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
89 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
90 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
91 EGL_TRUE,
92 EGL_NONE,
93 };
94
95 std::vector<const EGLint*> display_attributes_configs = {
96 d3d11_display_attributes,
97 d3d11_fl_9_3_display_attributes,
98 d3d11_warp_display_attributes,
99 };
100
101 PFNEGLGETPLATFORMDISPLAYEXTPROC egl_get_platform_display_EXT =
102 reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
103 ::eglGetProcAddress("eglGetPlatformDisplayEXT"));
104 if (!egl_get_platform_display_EXT) {
105 LogEGLError("eglGetPlatformDisplayEXT not available");
106 return false;
107 }
108
109 // Attempt to initialize ANGLE's renderer in order of: D3D11, D3D11 Feature
110 // Level 9_3 and finally D3D11 WARP.
111 for (auto config : display_attributes_configs) {
112 bool is_last = (config == display_attributes_configs.back());
113
114 display_ = egl_get_platform_display_EXT(EGL_PLATFORM_ANGLE_ANGLE,
115 EGL_DEFAULT_DISPLAY, config);
116
117 if (display_ == EGL_NO_DISPLAY) {
118 if (is_last) {
119 LogEGLError("Failed to get a compatible EGLdisplay");
120 return false;
121 }
122
123 // Try the next config.
124 continue;
125 }
126
127 if (::eglInitialize(display_, nullptr, nullptr) == EGL_FALSE) {
128 if (is_last) {
129 LogEGLError("Failed to initialize EGL via ANGLE");
130 return false;
131 }
132
133 // Try the next config.
134 continue;
135 }
136
137 return true;
138 }
139
140 FML_UNREACHABLE();
141 }
142
143 bool Manager::InitializeConfig() {
144 const EGLint config_attributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
145 EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
146 EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
147 EGL_NONE};
148
149 EGLint num_config = 0;
150
151 EGLBoolean result =
152 ::eglChooseConfig(display_, config_attributes, &config_, 1, &num_config);
153
154 if (result == EGL_TRUE && num_config > 0) {
155 return true;
156 }
157
158 LogEGLError("Failed to choose EGL config");
159 return false;
160 }
161
162 bool Manager::InitializeContexts() {
163 const EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
164
165 auto const render_context =
166 ::eglCreateContext(display_, config_, EGL_NO_CONTEXT, context_attributes);
167 if (render_context == EGL_NO_CONTEXT) {
168 LogEGLError("Failed to create EGL render context");
169 return false;
170 }
171
172 auto const resource_context =
173 ::eglCreateContext(display_, config_, render_context, context_attributes);
174 if (resource_context == EGL_NO_CONTEXT) {
175 LogEGLError("Failed to create EGL resource context");
176 return false;
177 }
178
179 render_context_ = std::make_unique<Context>(display_, render_context);
180 resource_context_ = std::make_unique<Context>(display_, resource_context);
181 return true;
182 }
183
184 bool Manager::InitializeDevice() {
185 const auto query_display_attrib_EXT =
186 reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
187 ::eglGetProcAddress("eglQueryDisplayAttribEXT"));
188 const auto query_device_attrib_EXT =
189 reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
190 ::eglGetProcAddress("eglQueryDeviceAttribEXT"));
191
192 if (query_display_attrib_EXT == nullptr ||
193 query_device_attrib_EXT == nullptr) {
194 return false;
195 }
196
197 EGLAttrib egl_device = 0;
198 EGLAttrib angle_device = 0;
199
200 auto result = query_display_attrib_EXT(display_, EGL_DEVICE_EXT, &egl_device);
201 if (result != EGL_TRUE) {
202 return false;
203 }
204
205 result = query_device_attrib_EXT(reinterpret_cast<EGLDeviceEXT>(egl_device),
206 EGL_D3D11_DEVICE_ANGLE, &angle_device);
207 if (result != EGL_TRUE) {
208 return false;
209 }
210
211 resolved_device_ = reinterpret_cast<ID3D11Device*>(angle_device);
212 return true;
213 }
214
215 void Manager::CleanUp() {
216 EGLBoolean result = EGL_FALSE;
217
218 // Needs to be reset before destroying the contexts.
219 resolved_device_.Reset();
220
221 // Needs to be reset before destroying the EGLDisplay.
222 render_context_.reset();
223 resource_context_.reset();
224
225 if (display_ != EGL_NO_DISPLAY) {
226 // Display is reused between instances so only terminate display
227 // if destroying last instance
228 if (instance_count_ == 1) {
229 ::eglTerminate(display_);
230 }
231 display_ = EGL_NO_DISPLAY;
232 }
233 }
234
235 bool Manager::IsValid() const {
236 return is_valid_;
237 }
238
239 std::unique_ptr<WindowSurface> Manager::CreateWindowSurface(HWND hwnd,
240 size_t width,
241 size_t height) {
242 if (!hwnd || !is_valid_) {
243 return nullptr;
244 }
245
246 // Disable ANGLE's automatic surface resizing and provide an explicit size.
247 // The surface will need to be destroyed and re-created if the HWND is
248 // resized.
249 const EGLint surface_attributes[] = {EGL_FIXED_SIZE_ANGLE,
250 EGL_TRUE,
251 EGL_WIDTH,
252 static_cast<EGLint>(width),
253 EGL_HEIGHT,
254 static_cast<EGLint>(height),
255 EGL_NONE};
256
257 auto const surface = ::eglCreateWindowSurface(
258 display_, config_, static_cast<EGLNativeWindowType>(hwnd),
259 surface_attributes);
260 if (surface == EGL_NO_SURFACE) {
261 LogEGLError("Surface creation failed.");
262 return nullptr;
263 }
264
265 return std::make_unique<WindowSurface>(display_, render_context_->GetHandle(),
266 surface, width, height);
267 }
268
269 bool Manager::HasContextCurrent() {
270 return ::eglGetCurrentContext() != EGL_NO_CONTEXT;
271 }
272
273 EGLSurface Manager::CreateSurfaceFromHandle(EGLenum handle_type,
274 EGLClientBuffer handle,
275 const EGLint* attributes) const {
276 return ::eglCreatePbufferFromClientBuffer(display_, handle_type, handle,
277 config_, attributes);
278 }
279
280 bool Manager::GetDevice(ID3D11Device** device) {
281 if (!resolved_device_) {
282 if (!InitializeDevice()) {
283 return false;
284 }
285 }
286
287 resolved_device_.CopyTo(device);
288 return (resolved_device_ != nullptr);
289 }
290
291 Context* Manager::render_context() const {
292 return render_context_.get();
293 }
294
295 Context* Manager::resource_context() const {
296 return resource_context_.get();
297 }
298
299 } // namespace egl
300 } // namespace flutter
flutter::egl::Manager::render_context
virtual Context * render_context() const
Definition: manager.cc:291
flutter::egl::Manager::IsValid
bool IsValid() const
Definition: manager.cc:235
flutter::egl::Manager::Manager
Manager()
Definition: manager.cc:26
egl.h
flutter::egl::Manager::HasContextCurrent
bool HasContextCurrent()
Definition: manager.cc:269
flutter::egl::Context
Definition: context.h:20
flutter::egl::Manager::~Manager
virtual ~Manager()
Definition: manager.cc:44
flutter::egl::Manager::CreateSurfaceFromHandle
EGLSurface CreateSurfaceFromHandle(EGLenum handle_type, EGLClientBuffer handle, const EGLint *attributes) const
Definition: manager.cc:273
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::egl::LogEGLError
void LogEGLError(std::string_view message)
Log the last EGL error with an error message.
Definition: egl.cc:55
flutter::egl::Manager::Create
static std::unique_ptr< Manager > Create()
Definition: manager.cc:17
manager.h
flutter::egl::Manager::resource_context
virtual Context * resource_context() const
Definition: manager.cc:295
flutter::egl::Manager::GetDevice
bool GetDevice(ID3D11Device **device)
Definition: manager.cc:280
flutter::egl::Manager::CreateWindowSurface
virtual std::unique_ptr< WindowSurface > CreateWindowSurface(HWND hwnd, size_t width, size_t height)
Definition: manager.cc:239