Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c0b11be

Browse files
committed
[Windows] Introduce egl::Surface and egl::WindowSurface
This reverts commit 963615c.
1 parent 436f91f commit c0b11be

16 files changed

+455
-217
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7242,6 +7242,10 @@ ORIGIN: ../../../flutter/shell/platform/windows/egl/manager.cc + ../../../flutte
72427242
ORIGIN: ../../../flutter/shell/platform/windows/egl/manager.h + ../../../flutter/LICENSE
72437243
ORIGIN: ../../../flutter/shell/platform/windows/egl/proc_table.cc + ../../../flutter/LICENSE
72447244
ORIGIN: ../../../flutter/shell/platform/windows/egl/proc_table.h + ../../../flutter/LICENSE
7245+
ORIGIN: ../../../flutter/shell/platform/windows/egl/surface.cc + ../../../flutter/LICENSE
7246+
ORIGIN: ../../../flutter/shell/platform/windows/egl/surface.h + ../../../flutter/LICENSE
7247+
ORIGIN: ../../../flutter/shell/platform/windows/egl/window_surface.cc + ../../../flutter/LICENSE
7248+
ORIGIN: ../../../flutter/shell/platform/windows/egl/window_surface.h + ../../../flutter/LICENSE
72457249
ORIGIN: ../../../flutter/shell/platform/windows/event_watcher.cc + ../../../flutter/LICENSE
72467250
ORIGIN: ../../../flutter/shell/platform/windows/event_watcher.h + ../../../flutter/LICENSE
72477251
ORIGIN: ../../../flutter/shell/platform/windows/external_texture.h + ../../../flutter/LICENSE
@@ -10117,6 +10121,10 @@ FILE: ../../../flutter/shell/platform/windows/egl/manager.cc
1011710121
FILE: ../../../flutter/shell/platform/windows/egl/manager.h
1011810122
FILE: ../../../flutter/shell/platform/windows/egl/proc_table.cc
1011910123
FILE: ../../../flutter/shell/platform/windows/egl/proc_table.h
10124+
FILE: ../../../flutter/shell/platform/windows/egl/surface.cc
10125+
FILE: ../../../flutter/shell/platform/windows/egl/surface.h
10126+
FILE: ../../../flutter/shell/platform/windows/egl/window_surface.cc
10127+
FILE: ../../../flutter/shell/platform/windows/egl/window_surface.h
1012010128
FILE: ../../../flutter/shell/platform/windows/event_watcher.cc
1012110129
FILE: ../../../flutter/shell/platform/windows/event_watcher.h
1012210130
FILE: ../../../flutter/shell/platform/windows/external_texture.h

shell/platform/windows/BUILD.gn

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ source_set("flutter_windows_source") {
5959
"egl/manager.h",
6060
"egl/proc_table.cc",
6161
"egl/proc_table.h",
62+
"egl/surface.cc",
63+
"egl/surface.h",
64+
"egl/window_surface.cc",
65+
"egl/window_surface.h",
6266
"event_watcher.cc",
6367
"event_watcher.h",
6468
"external_texture.h",
@@ -209,6 +213,7 @@ executable("flutter_windows_unittests") {
209213
"testing/egl/mock_context.h",
210214
"testing/egl/mock_manager.h",
211215
"testing/egl/mock_proc_table.h",
216+
"testing/egl/mock_window_surface.h",
212217
"testing/engine_modifier.h",
213218
"testing/flutter_window_test.cc",
214219
"testing/flutter_window_test.h",

shell/platform/windows/compositor_opengl.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ bool CompositorOpenGL::Present(const FlutterLayer** layers,
9797
return false;
9898
}
9999

100+
if (!engine_->egl_manager()->surface() ||
101+
!engine_->egl_manager()->surface()->IsValid()) {
102+
return false;
103+
}
104+
100105
// Clear the view if there are no layers to present.
101106
if (layers_count == 0) {
102107
// Normally the compositor is initialized when the first backing store is
@@ -128,7 +133,7 @@ bool CompositorOpenGL::Present(const FlutterLayer** layers,
128133
return false;
129134
}
130135

131-
if (!engine_->egl_manager()->MakeCurrent()) {
136+
if (!engine_->egl_manager()->surface()->MakeCurrent()) {
132137
return false;
133138
}
134139

@@ -154,7 +159,7 @@ bool CompositorOpenGL::Present(const FlutterLayer** layers,
154159
GL_NEAREST // filter
155160
);
156161

157-
if (!engine_->egl_manager()->SwapBuffers()) {
162+
if (!engine_->egl_manager()->surface()->SwapBuffers()) {
158163
return false;
159164
}
160165

@@ -165,7 +170,7 @@ bool CompositorOpenGL::Present(const FlutterLayer** layers,
165170
bool CompositorOpenGL::Initialize() {
166171
FML_DCHECK(!is_initialized_);
167172

168-
if (!engine_->egl_manager()->MakeCurrent()) {
173+
if (!engine_->egl_manager()->surface()->MakeCurrent()) {
169174
return false;
170175
}
171176

@@ -186,14 +191,14 @@ bool CompositorOpenGL::ClearSurface() {
186191
// Resize the surface if needed.
187192
engine_->view()->OnEmptyFrameGenerated();
188193

189-
if (!engine_->egl_manager()->MakeCurrent()) {
194+
if (!engine_->egl_manager()->surface()->MakeCurrent()) {
190195
return false;
191196
}
192197

193198
gl_->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
194199
gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
195200

196-
if (!engine_->egl_manager()->SwapBuffers()) {
201+
if (!engine_->egl_manager()->surface()->SwapBuffers()) {
197202
return false;
198203
}
199204

shell/platform/windows/compositor_opengl_unittests.cc

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "flutter/shell/platform/windows/egl/manager.h"
1111
#include "flutter/shell/platform/windows/flutter_windows_view.h"
1212
#include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
13+
#include "flutter/shell/platform/windows/testing/egl/mock_window_surface.h"
1314
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
1415
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
1516
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
@@ -65,10 +66,14 @@ class CompositorOpenGLTest : public WindowsTest {
6566
protected:
6667
FlutterWindowsEngine* engine() { return engine_.get(); }
6768
egl::MockManager* egl_manager() { return egl_manager_; }
69+
egl::MockWindowSurface* surface() { return surface_.get(); }
6870

6971
void UseHeadlessEngine() {
7072
auto egl_manager = std::make_unique<egl::MockManager>();
7173
egl_manager_ = egl_manager.get();
74+
surface_ = std::make_unique<egl::MockWindowSurface>();
75+
76+
EXPECT_CALL(*egl_manager_, surface).WillRepeatedly(Return(surface_.get()));
7277

7378
FlutterWindowsEngineBuilder builder{GetContext()};
7479

@@ -92,6 +97,7 @@ class CompositorOpenGLTest : public WindowsTest {
9297
private:
9398
std::unique_ptr<FlutterWindowsEngine> engine_;
9499
std::unique_ptr<FlutterWindowsView> view_;
100+
std::unique_ptr<egl::MockWindowSurface> surface_;
95101
egl::MockManager* egl_manager_;
96102

97103
FML_DISALLOW_COPY_AND_ASSIGN(CompositorOpenGLTest);
@@ -107,7 +113,7 @@ TEST_F(CompositorOpenGLTest, CreateBackingStore) {
107113
FlutterBackingStoreConfig config = {};
108114
FlutterBackingStore backing_store = {};
109115

110-
EXPECT_CALL(*egl_manager(), MakeCurrent).WillOnce(Return(true));
116+
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
111117
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
112118
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
113119
}
@@ -120,7 +126,7 @@ TEST_F(CompositorOpenGLTest, InitializationFailure) {
120126
FlutterBackingStoreConfig config = {};
121127
FlutterBackingStore backing_store = {};
122128

123-
EXPECT_CALL(*egl_manager(), MakeCurrent).WillOnce(Return(false));
129+
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(false));
124130
EXPECT_FALSE(compositor.CreateBackingStore(config, &backing_store));
125131
}
126132

@@ -132,16 +138,16 @@ TEST_F(CompositorOpenGLTest, Present) {
132138
FlutterBackingStoreConfig config = {};
133139
FlutterBackingStore backing_store = {};
134140

135-
EXPECT_CALL(*egl_manager(), MakeCurrent).WillOnce(Return(true));
141+
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
136142
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
137143

138144
FlutterLayer layer = {};
139145
layer.type = kFlutterLayerContentTypeBackingStore;
140146
layer.backing_store = &backing_store;
141147
const FlutterLayer* layer_ptr = &layer;
142148

143-
EXPECT_CALL(*egl_manager(), MakeCurrent).WillOnce(Return(true));
144-
EXPECT_CALL(*egl_manager(), SwapBuffers).WillOnce(Return(true));
149+
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
150+
EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
145151
EXPECT_TRUE(compositor.Present(&layer_ptr, 1));
146152

147153
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
@@ -154,10 +160,8 @@ TEST_F(CompositorOpenGLTest, PresentEmpty) {
154160

155161
// The context will be bound twice: first to initialize the compositor, second
156162
// to clear the surface.
157-
EXPECT_CALL(*egl_manager(), MakeCurrent)
158-
.Times(2)
159-
.WillRepeatedly(Return(true));
160-
EXPECT_CALL(*egl_manager(), SwapBuffers).WillOnce(Return(true));
163+
EXPECT_CALL(*surface(), MakeCurrent).Times(2).WillRepeatedly(Return(true));
164+
EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
161165
EXPECT_TRUE(compositor.Present(nullptr, 0));
162166
}
163167

@@ -169,7 +173,7 @@ TEST_F(CompositorOpenGLTest, HeadlessPresentIgnored) {
169173
FlutterBackingStoreConfig config = {};
170174
FlutterBackingStore backing_store = {};
171175

172-
EXPECT_CALL(*egl_manager(), MakeCurrent).WillOnce(Return(true));
176+
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
173177
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
174178

175179
FlutterLayer layer = {};

shell/platform/windows/egl/context.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace egl {
1414

1515
// An EGL context to interact with OpenGL.
1616
//
17-
// This enables automatic eror logging and mocking.
17+
// This enables automatic error logging and mocking.
1818
//
1919
// Flutter Windows uses this to create render and resource contexts.
2020
class Context {

shell/platform/windows/egl/manager.cc

Lines changed: 40 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -263,116 +263,78 @@ bool Manager::IsValid() const {
263263
return is_valid_;
264264
}
265265

266-
bool Manager::CreateSurface(HWND hwnd, EGLint width, EGLint height) {
266+
bool Manager::CreateWindowSurface(HWND hwnd, size_t width, size_t height) {
267+
FML_DCHECK(surface_ == nullptr || !surface_->IsValid());
268+
267269
if (!hwnd || !is_valid_) {
268270
return false;
269271
}
270272

271-
EGLSurface surface = EGL_NO_SURFACE;
272-
273273
// Disable ANGLE's automatic surface resizing and provide an explicit size.
274274
// The surface will need to be destroyed and re-created if the HWND is
275275
// resized.
276-
const EGLint surface_attributes[] = {
277-
EGL_FIXED_SIZE_ANGLE, EGL_TRUE, EGL_WIDTH, width,
278-
EGL_HEIGHT, height, EGL_NONE};
279-
280-
surface = ::eglCreateWindowSurface(display_, config_,
281-
static_cast<EGLNativeWindowType>(hwnd),
282-
surface_attributes);
276+
const EGLint surface_attributes[] = {EGL_FIXED_SIZE_ANGLE,
277+
EGL_TRUE,
278+
EGL_WIDTH,
279+
static_cast<EGLint>(width),
280+
EGL_HEIGHT,
281+
static_cast<EGLint>(height),
282+
EGL_NONE};
283+
284+
auto const surface = ::eglCreateWindowSurface(
285+
display_, config_, static_cast<EGLNativeWindowType>(hwnd),
286+
surface_attributes);
283287
if (surface == EGL_NO_SURFACE) {
284288
LogEGLError("Surface creation failed.");
285289
return false;
286290
}
287291

288-
surface_width_ = width;
289-
surface_height_ = height;
290-
surface_ = surface;
292+
surface_ = std::make_unique<WindowSurface>(
293+
display_, render_context_->GetHandle(), surface, width, height);
291294
return true;
292295
}
293296

294-
void Manager::ResizeSurface(HWND hwnd,
295-
EGLint width,
296-
EGLint height,
297-
bool vsync_enabled) {
298-
EGLint existing_width, existing_height;
299-
GetSurfaceDimensions(&existing_width, &existing_height);
300-
if (width != existing_width || height != existing_height) {
301-
surface_width_ = width;
302-
surface_height_ = height;
297+
void Manager::ResizeWindowSurface(HWND hwnd, size_t width, size_t height) {
298+
FML_CHECK(surface_ != nullptr);
303299

300+
auto const existing_width = surface_->width();
301+
auto const existing_height = surface_->height();
302+
auto const existing_vsync = surface_->vsync_enabled();
303+
304+
if (width != existing_width || height != existing_height) {
304305
// TODO: Destroying the surface and re-creating it is expensive.
305306
// Ideally this would use ANGLE's automatic surface sizing instead.
306307
// See: https://github.com/flutter/flutter/issues/79427
307-
render_context_->ClearCurrent();
308-
DestroySurface();
309-
if (!CreateSurface(hwnd, width, height)) {
310-
FML_LOG(ERROR) << "Manager::ResizeSurface failed to create surface";
308+
if (!surface_->Destroy()) {
309+
FML_LOG(ERROR) << "Manager::ResizeSurface failed to destroy surface";
310+
return;
311311
}
312-
}
313312

314-
SetVSyncEnabled(vsync_enabled);
315-
}
316-
317-
void Manager::GetSurfaceDimensions(EGLint* width, EGLint* height) {
318-
if (surface_ == EGL_NO_SURFACE || !is_valid_) {
319-
*width = 0;
320-
*height = 0;
321-
return;
322-
}
323-
324-
// This avoids eglQuerySurface as ideally surfaces would be automatically
325-
// sized by ANGLE to avoid expensive surface destroy & re-create. With
326-
// automatic sizing, ANGLE could resize the surface before Flutter asks it to,
327-
// which would break resize redraw synchronization.
328-
*width = surface_width_;
329-
*height = surface_height_;
330-
}
313+
if (!CreateWindowSurface(hwnd, width, height)) {
314+
FML_LOG(ERROR) << "Manager::ResizeSurface failed to create surface";
315+
return;
316+
}
331317

332-
void Manager::DestroySurface() {
333-
if (display_ != EGL_NO_DISPLAY && surface_ != EGL_NO_SURFACE) {
334-
::eglDestroySurface(display_, surface_);
318+
if (!surface_->SetVSyncEnabled(existing_vsync)) {
319+
// Surfaces block until the v-blank by default.
320+
// Failing to update the vsync might result in unnecessary blocking.
321+
// This regresses performance but not correctness.
322+
FML_LOG(ERROR) << "Manager::ResizeSurface failed to set vsync";
323+
}
335324
}
336-
surface_ = EGL_NO_SURFACE;
337325
}
338326

339327
bool Manager::HasContextCurrent() {
340328
return ::eglGetCurrentContext() != EGL_NO_CONTEXT;
341329
}
342330

343-
bool Manager::MakeCurrent() {
344-
return (::eglMakeCurrent(display_, surface_, surface_,
345-
render_context_->GetHandle()) == EGL_TRUE);
346-
}
347-
348-
bool Manager::SwapBuffers() {
349-
return (::eglSwapBuffers(display_, surface_));
350-
}
351-
352331
EGLSurface Manager::CreateSurfaceFromHandle(EGLenum handle_type,
353332
EGLClientBuffer handle,
354333
const EGLint* attributes) const {
355334
return ::eglCreatePbufferFromClientBuffer(display_, handle_type, handle,
356335
config_, attributes);
357336
}
358337

359-
void Manager::SetVSyncEnabled(bool enabled) {
360-
if (!MakeCurrent()) {
361-
LogEGLError("Unable to make surface current to update the swap interval");
362-
return;
363-
}
364-
365-
// OpenGL swap intervals can be used to prevent screen tearing.
366-
// If enabled, the raster thread blocks until the v-blank.
367-
// This is unnecessary if DWM composition is enabled.
368-
// See: https://www.khronos.org/opengl/wiki/Swap_Interval
369-
// See: https://learn.microsoft.com/windows/win32/dwm/composition-ovw
370-
if (::eglSwapInterval(display_, enabled ? 1 : 0) != EGL_TRUE) {
371-
LogEGLError("Unable to update the swap interval");
372-
return;
373-
}
374-
}
375-
376338
bool Manager::GetDevice(ID3D11Device** device) {
377339
if (!resolved_device_) {
378340
if (!InitializeDevice()) {
@@ -392,5 +354,9 @@ Context* Manager::resource_context() const {
392354
return resource_context_.get();
393355
}
394356

357+
WindowSurface* Manager::surface() const {
358+
return surface_.get();
359+
}
360+
395361
} // namespace egl
396362
} // namespace flutter

0 commit comments

Comments
 (0)