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 namespace flutter {
8
AngleSurfaceManager()9 AngleSurfaceManager::AngleSurfaceManager()
10 : egl_config_(nullptr),
11 egl_display_(EGL_NO_DISPLAY),
12 egl_context_(EGL_NO_CONTEXT) {
13 initialize_succeeded_ = Initialize();
14 }
15
~AngleSurfaceManager()16 AngleSurfaceManager::~AngleSurfaceManager() {
17 CleanUp();
18 }
19
Initialize()20 bool AngleSurfaceManager::Initialize() {
21 const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
22 EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
23 EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
24 EGL_NONE};
25
26 const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
27 EGL_NONE};
28
29 const EGLint default_display_attributes[] = {
30 // These are prefered display attributes and request ANGLE's D3D11
31 // renderer. eglInitialize will only succeed with these attributes if the
32 // hardware supports D3D11 Feature Level 10_0+.
33 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
34 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
35
36 // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will
37 // enable ANGLE to automatically call the IDXGIDevice3::Trim method on
38 // behalf of the application when it gets suspended.
39 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
40 EGL_TRUE,
41 EGL_NONE,
42 };
43
44 const EGLint fl9_3_display_attributes[] = {
45 // These are used to request ANGLE's D3D11 renderer, with D3D11 Feature
46 // Level 9_3.
47 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
48 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
49 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
50 9,
51 EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
52 3,
53 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
54 EGL_TRUE,
55 EGL_NONE,
56 };
57
58 const EGLint warp_display_attributes[] = {
59 // These attributes request D3D11 WARP (software rendering fallback) as a
60 // last resort.
61 EGL_PLATFORM_ANGLE_TYPE_ANGLE,
62 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
63 EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
64 EGL_TRUE,
65 EGL_NONE,
66 };
67
68 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
69 reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
70 eglGetProcAddress("eglGetPlatformDisplayEXT"));
71 if (!eglGetPlatformDisplayEXT) {
72 OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay");
73 return false;
74 }
75
76 // Try to initialize EGL to D3D11 Feature Level 10_0+.
77 egl_display_ =
78 eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY,
79 default_display_attributes);
80 if (egl_display_ == EGL_NO_DISPLAY) {
81 OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay");
82 return false;
83 }
84
85 if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
86 // If above failed, try to initialize EGL to D3D11 Feature Level 9_3, if
87 // 10_0+ is unavailable.
88 egl_display_ =
89 eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY,
90 fl9_3_display_attributes);
91 if (egl_display_ == EGL_NO_DISPLAY) {
92 OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay");
93 return false;
94 }
95
96 if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
97 // If all else fails, attempt D3D11 Feature Level 11_0 on WARP as a last
98 // resort
99 egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
100 EGL_DEFAULT_DISPLAY,
101 warp_display_attributes);
102 if (egl_display_ == EGL_NO_DISPLAY) {
103 OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay");
104 return false;
105 }
106
107 if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
108 OutputDebugString(L"EGL: Failed to initialize EGL");
109 return false;
110 }
111 }
112 }
113
114 EGLint numConfigs = 0;
115 if ((eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1,
116 &numConfigs) == EGL_FALSE) ||
117 (numConfigs == 0)) {
118 OutputDebugString(L"EGL: Failed to choose first context");
119 return false;
120 }
121
122 egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT,
123 display_context_attributes);
124 if (egl_context_ == EGL_NO_CONTEXT) {
125 OutputDebugString(L"EGL: Failed to create EGL context");
126 return false;
127 }
128
129 return true;
130 }
131
CleanUp()132 void AngleSurfaceManager::CleanUp() {
133 if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) {
134 eglDestroyContext(egl_display_, egl_context_);
135 egl_context_ = EGL_NO_CONTEXT;
136 }
137
138 if (egl_display_ != EGL_NO_DISPLAY) {
139 eglTerminate(egl_display_);
140 egl_display_ = EGL_NO_DISPLAY;
141 }
142 }
143
CreateSurface(HWND window)144 EGLSurface AngleSurfaceManager::CreateSurface(HWND window) {
145 if (!window || !initialize_succeeded_) {
146 return EGL_NO_SURFACE;
147 }
148
149 EGLSurface surface = EGL_NO_SURFACE;
150
151 const EGLint surfaceAttributes[] = {EGL_NONE};
152
153 surface = eglCreateWindowSurface(egl_display_, egl_config_,
154 static_cast<EGLNativeWindowType>(window),
155 surfaceAttributes);
156 return surface;
157 }
158
GetSurfaceDimensions(const EGLSurface surface,EGLint * width,EGLint * height)159 void AngleSurfaceManager::GetSurfaceDimensions(const EGLSurface surface,
160 EGLint* width,
161 EGLint* height) {
162 if (surface == EGL_NO_SURFACE || !initialize_succeeded_) {
163 width = 0;
164 height = 0;
165 return;
166 }
167
168 eglQuerySurface(egl_display_, surface, EGL_WIDTH, width);
169 eglQuerySurface(egl_display_, surface, EGL_HEIGHT, height);
170 }
171
DestroySurface(const EGLSurface surface)172 void AngleSurfaceManager::DestroySurface(const EGLSurface surface) {
173 if (egl_display_ != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) {
174 eglDestroySurface(egl_display_, surface);
175 }
176 }
177
MakeCurrent(const EGLSurface surface)178 bool AngleSurfaceManager::MakeCurrent(const EGLSurface surface) {
179 return (eglMakeCurrent(egl_display_, surface, surface, egl_context_) ==
180 EGL_TRUE);
181 }
182
SwapBuffers(const EGLSurface surface)183 EGLBoolean AngleSurfaceManager::SwapBuffers(const EGLSurface surface) {
184 return (eglSwapBuffers(egl_display_, surface));
185 }
186
187 } // namespace flutter