Flutter Engine
angle_surface_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/angle_surface_manager.h"
6 
7 #include <iostream>
8 
9 namespace flutter {
10 
12  : egl_config_(nullptr),
13  egl_display_(EGL_NO_DISPLAY),
14  egl_context_(EGL_NO_CONTEXT) {
15  initialize_succeeded_ = Initialize();
16 }
17 
19  CleanUp();
20 }
21 
22 bool AngleSurfaceManager::Initialize() {
23  const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
24  EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
25  EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
26  EGL_NONE};
27 
28  const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
29  EGL_NONE};
30 
31  const EGLint default_display_attributes[] = {
32  // These are prefered display attributes and request ANGLE's D3D11
33  // renderer. eglInitialize will only succeed with these attributes if the
34  // hardware supports D3D11 Feature Level 10_0+.
35  EGL_PLATFORM_ANGLE_TYPE_ANGLE,
36  EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
37 
38  // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will
39  // enable ANGLE to automatically call the IDXGIDevice3::Trim method on
40  // behalf of the application when it gets suspended.
41  EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
42  EGL_TRUE,
43  EGL_NONE,
44  };
45 
46  const EGLint fl9_3_display_attributes[] = {
47  // These are used to request ANGLE's D3D11 renderer, with D3D11 Feature
48  // Level 9_3.
49  EGL_PLATFORM_ANGLE_TYPE_ANGLE,
50  EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
51  EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
52  9,
53  EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
54  3,
55  EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
56  EGL_TRUE,
57  EGL_NONE,
58  };
59 
60  const EGLint warp_display_attributes[] = {
61  // These attributes request D3D11 WARP (software rendering fallback) as a
62  // last resort.
63  EGL_PLATFORM_ANGLE_TYPE_ANGLE,
64  EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
65  EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
66  EGL_TRUE,
67  EGL_NONE,
68  };
69 
70  PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
71  reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
72  eglGetProcAddress("eglGetPlatformDisplayEXT"));
73  if (!eglGetPlatformDisplayEXT) {
74  std::cerr << "EGL: eglGetPlatformDisplayEXT not available" << std::endl;
75  return false;
76  }
77 
78  // Try to initialize EGL to D3D11 Feature Level 10_0+.
79  egl_display_ =
80  eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY,
81  default_display_attributes);
82  if (egl_display_ == EGL_NO_DISPLAY) {
83  std::cerr << "EGL: Failed to get a compatible EGLdisplay" << std::endl;
84  return false;
85  }
86 
87  if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
88  // If above failed, try to initialize EGL to D3D11 Feature Level 9_3, if
89  // 10_0+ is unavailable.
90  egl_display_ =
91  eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY,
92  fl9_3_display_attributes);
93  if (egl_display_ == EGL_NO_DISPLAY) {
94  std::cerr << "EGL: Failed to get a compatible 9.3 EGLdisplay"
95  << std::endl;
96  return false;
97  }
98 
99  if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
100  // If all else fails, attempt D3D11 Feature Level 11_0 on WARP as a last
101  // resort
102  egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
103  EGL_DEFAULT_DISPLAY,
104  warp_display_attributes);
105  if (egl_display_ == EGL_NO_DISPLAY) {
106  std::cerr << "EGL: Failed to get a compatible WARP EGLdisplay"
107  << std::endl;
108  return false;
109  }
110 
111  if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
112  std::cerr << "EGL: Failed to initialize EGL" << std::endl;
113  return false;
114  }
115  }
116  }
117 
118  EGLint numConfigs = 0;
119  if ((eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1,
120  &numConfigs) == EGL_FALSE) ||
121  (numConfigs == 0)) {
122  std::cerr << "EGL: Failed to choose first context" << std::endl;
123  return false;
124  }
125 
126  egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT,
127  display_context_attributes);
128  if (egl_context_ == EGL_NO_CONTEXT) {
129  std::cerr << "EGL: Failed to create EGL context" << std::endl;
130  return false;
131  }
132 
133  egl_resource_context_ = eglCreateContext(
134  egl_display_, egl_config_, egl_context_, display_context_attributes);
135 
136  if (egl_resource_context_ == EGL_NO_CONTEXT) {
137  std::cerr << "EGL: Failed to create EGL resource context" << std::endl;
138  return false;
139  }
140 
141  return true;
142 }
143 
144 void AngleSurfaceManager::CleanUp() {
145  EGLBoolean result = EGL_FALSE;
146 
147  if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) {
148  result = eglDestroyContext(egl_display_, egl_context_);
149  egl_context_ = EGL_NO_CONTEXT;
150 
151  if (result == EGL_FALSE) {
152  std::cerr << "EGL: Failed to destroy context" << std::endl;
153  }
154  }
155 
156  if (egl_display_ != EGL_NO_DISPLAY &&
157  egl_resource_context_ != EGL_NO_CONTEXT) {
158  result = eglDestroyContext(egl_display_, egl_resource_context_);
159  egl_resource_context_ = EGL_NO_CONTEXT;
160 
161  if (result == EGL_FALSE) {
162  std::cerr << "EGL: Failed to destroy resource context" << std::endl;
163  }
164  }
165 
166  if (egl_display_ != EGL_NO_DISPLAY) {
167  eglTerminate(egl_display_);
168  egl_display_ = EGL_NO_DISPLAY;
169  }
170 }
171 
173  EGLint width,
174  EGLint height) {
175  if (!render_target || !initialize_succeeded_) {
176  return false;
177  }
178 
179  EGLSurface surface = EGL_NO_SURFACE;
180 
181  // Disable Angle's automatic surface sizing logic and provide and exlicit
182  // size. AngleSurfaceManager is responsible for initiating Angle surface size
183  // changes to avoid race conditions with rendering when automatic mode is
184  // used.
185  const EGLint surfaceAttributes[] = {
186  EGL_FIXED_SIZE_ANGLE, EGL_TRUE, EGL_WIDTH, width,
187  EGL_HEIGHT, height, EGL_NONE};
188 
189  surface = eglCreateWindowSurface(
190  egl_display_, egl_config_,
191  static_cast<EGLNativeWindowType>(std::get<HWND>(*render_target)),
192  surfaceAttributes);
193  if (surface == EGL_NO_SURFACE) {
194  std::cerr << "Surface creation failed." << std::endl;
195  }
196 
197  render_surface_ = surface;
198  return true;
199 }
200 
202  EGLint width,
203  EGLint height) {
204  EGLint existing_width, existing_height;
205  GetSurfaceDimensions(&existing_width, &existing_height);
206  if (width != existing_width || height != existing_height) {
207  // Destroy existing surface with previous stale dimensions and create new
208  // surface at new size. Since the Windows compositor retains the front
209  // buffer until the new surface has been presented, no need to manually
210  // preserve the previous surface contents. This resize approach could be
211  // further optimized if Angle exposed a public entrypoint for
212  // SwapChain11::reset or SwapChain11::resize.
213  DestroySurface();
214  if (!CreateSurface(render_target, width, height)) {
215  std::cerr << "AngleSurfaceManager::ResizeSurface failed to create surface"
216  << std::endl;
217  }
218  }
219 }
220 
222  if (render_surface_ == EGL_NO_SURFACE || !initialize_succeeded_) {
223  width = 0;
224  height = 0;
225  return;
226  }
227 
228  eglQuerySurface(egl_display_, render_surface_, EGL_WIDTH, width);
229  eglQuerySurface(egl_display_, render_surface_, EGL_HEIGHT, height);
230 }
231 
233  if (egl_display_ != EGL_NO_DISPLAY && render_surface_ != EGL_NO_SURFACE) {
234  eglDestroySurface(egl_display_, render_surface_);
235  }
236  render_surface_ = EGL_NO_SURFACE;
237 }
238 
240  return (eglMakeCurrent(egl_display_, render_surface_, render_surface_,
241  egl_context_) == EGL_TRUE);
242 }
243 
245  return (eglMakeCurrent(egl_display_, nullptr, nullptr, egl_context_) ==
246  EGL_TRUE);
247 }
248 
250  return (eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
251  egl_resource_context_) == EGL_TRUE);
252 }
253 
255  return (eglSwapBuffers(egl_display_, render_surface_));
256 }
257 
258 } // namespace flutter
void GetSurfaceDimensions(EGLint *width, EGLint *height)
std::variant< HWND > WindowsRenderTarget
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
Definition: mock_egl.cc:263
void(*)(void) eglGetProcAddress(const char *procname)
Definition: mock_egl.cc:258
void ResizeSurface(WindowsRenderTarget *render_target, EGLint width, EGLint height)
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
Definition: mock_egl.cc:121
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
Definition: mock_egl.cc:142
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
Definition: mock_egl.cc:306
int32_t height
int32_t width
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
Definition: mock_egl.cc:316
bool CreateSurface(WindowsRenderTarget *render_target, EGLint width, EGLint height)
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
Definition: mock_egl.cc:95