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

Commit d44462a

Browse files
authored
[Windows] Prepare to add/remove views (#51908)
_This is a refactoring with no semantic changes._ Prepare the Windows embedder to add/remove views. In a multi-view world, the platform thread can remove a view while the raster thread presenting to the same view. A lock will be introduced to ensure this does not happen. This shuffles the code around so that the engine can acquire the lock before the compositor presents to the view. Prepares for flutter/flutter#138179 Part of flutter/flutter#142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent dcc99d6 commit d44462a

11 files changed

Lines changed: 173 additions & 171 deletions

shell/platform/windows/compositor.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
namespace flutter {
1111

12+
class FlutterWindowsView;
13+
1214
// Enables the Flutter engine to render content on Windows.
1315
//
1416
// The engine uses this to:
@@ -31,7 +33,7 @@ class Compositor {
3133
virtual bool CollectBackingStore(const FlutterBackingStore* store) = 0;
3234

3335
// Present Flutter content and platform views onto the view.
34-
virtual bool Present(FlutterViewId view_id,
36+
virtual bool Present(FlutterWindowsView* view,
3537
const FlutterLayer** layers,
3638
size_t layers_count) = 0;
3739
};

shell/platform/windows/compositor_opengl.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,10 @@ bool CompositorOpenGL::CollectBackingStore(const FlutterBackingStore* store) {
9292
return true;
9393
}
9494

95-
bool CompositorOpenGL::Present(FlutterViewId view_id,
95+
bool CompositorOpenGL::Present(FlutterWindowsView* view,
9696
const FlutterLayer** layers,
9797
size_t layers_count) {
98-
FlutterWindowsView* view = engine_->view(view_id);
99-
if (!view) {
100-
return false;
101-
}
98+
FML_DCHECK(view != nullptr);
10299

103100
// Clear the view if there are no layers to present.
104101
if (layers_count == 0) {

shell/platform/windows/compositor_opengl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <memory>
99

10+
#include "flutter/fml/macros.h"
1011
#include "flutter/impeller/renderer/backend/gles/proc_table_gles.h"
1112
#include "flutter/shell/platform/embedder/embedder.h"
1213
#include "flutter/shell/platform/windows/compositor.h"
@@ -28,7 +29,7 @@ class CompositorOpenGL : public Compositor {
2829
bool CollectBackingStore(const FlutterBackingStore* store) override;
2930

3031
/// |Compositor|
31-
bool Present(FlutterViewId view_id,
32+
bool Present(FlutterWindowsView* view,
3233
const FlutterLayer** layers,
3334
size_t layers_count) override;
3435

@@ -56,6 +57,8 @@ class CompositorOpenGL : public Compositor {
5657

5758
// Clear the view's surface and removes any previously presented layers.
5859
bool Clear(FlutterWindowsView* view);
60+
61+
FML_DISALLOW_COPY_AND_ASSIGN(CompositorOpenGL);
5962
};
6063

6164
} // namespace flutter

shell/platform/windows/compositor_opengl_unittests.cc

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ class CompositorOpenGLTest : public WindowsTest {
108108
ViewModifier modifier{view_.get()};
109109
modifier.SetSurface(std::move(surface));
110110
}
111-
112-
EngineModifier modifier{engine_.get()};
113-
modifier.SetImplicitView(view_.get());
114111
}
115112

116113
private:
@@ -169,7 +166,7 @@ TEST_F(CompositorOpenGLTest, Present) {
169166
EXPECT_CALL(*surface(), IsValid).WillRepeatedly(Return(true));
170167
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
171168
EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
172-
EXPECT_TRUE(compositor.Present(view()->view_id(), &layer_ptr, 1));
169+
EXPECT_TRUE(compositor.Present(view(), &layer_ptr, 1));
173170

174171
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
175172
}
@@ -185,53 +182,7 @@ TEST_F(CompositorOpenGLTest, PresentEmpty) {
185182
EXPECT_CALL(*surface(), IsValid).WillRepeatedly(Return(true));
186183
EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
187184
EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
188-
EXPECT_TRUE(compositor.Present(view()->view_id(), nullptr, 0));
189-
}
190-
191-
TEST_F(CompositorOpenGLTest, HeadlessPresentIgnored) {
192-
UseHeadlessEngine();
193-
194-
auto compositor = CompositorOpenGL{engine(), kMockResolver};
195-
196-
FlutterBackingStoreConfig config = {};
197-
FlutterBackingStore backing_store = {};
198-
199-
EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
200-
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
201-
202-
FlutterLayer layer = {};
203-
layer.type = kFlutterLayerContentTypeBackingStore;
204-
layer.backing_store = &backing_store;
205-
const FlutterLayer* layer_ptr = &layer;
206-
207-
EXPECT_FALSE(compositor.Present(kImplicitViewId, &layer_ptr, 1));
208-
209-
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
210-
}
211-
212-
TEST_F(CompositorOpenGLTest, UnknownViewIgnored) {
213-
UseEngineWithView();
214-
215-
auto compositor = CompositorOpenGL{engine(), kMockResolver};
216-
217-
FlutterBackingStoreConfig config = {};
218-
FlutterBackingStore backing_store = {};
219-
220-
EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
221-
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
222-
223-
FlutterLayer layer = {};
224-
layer.type = kFlutterLayerContentTypeBackingStore;
225-
layer.backing_store = &backing_store;
226-
const FlutterLayer* layer_ptr = &layer;
227-
228-
FlutterViewId unknown_view_id = 123;
229-
ASSERT_NE(view()->view_id(), unknown_view_id);
230-
ASSERT_EQ(engine()->view(unknown_view_id), nullptr);
231-
232-
EXPECT_FALSE(compositor.Present(unknown_view_id, &layer_ptr, 1));
233-
234-
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
185+
EXPECT_TRUE(compositor.Present(view(), nullptr, 0));
235186
}
236187

237188
TEST_F(CompositorOpenGLTest, NoSurfaceIgnored) {
@@ -250,7 +201,7 @@ TEST_F(CompositorOpenGLTest, NoSurfaceIgnored) {
250201
layer.backing_store = &backing_store;
251202
const FlutterLayer* layer_ptr = &layer;
252203

253-
EXPECT_FALSE(compositor.Present(view()->view_id(), &layer_ptr, 1));
204+
EXPECT_FALSE(compositor.Present(view(), &layer_ptr, 1));
254205

255206
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
256207
}

shell/platform/windows/compositor_software.cc

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
namespace flutter {
1111

12-
CompositorSoftware::CompositorSoftware(FlutterWindowsEngine* engine)
13-
: engine_(engine) {}
12+
CompositorSoftware::CompositorSoftware() {}
1413

1514
bool CompositorSoftware::CreateBackingStore(
1615
const FlutterBackingStoreConfig& config,
@@ -38,13 +37,10 @@ bool CompositorSoftware::CollectBackingStore(const FlutterBackingStore* store) {
3837
return true;
3938
}
4039

41-
bool CompositorSoftware::Present(FlutterViewId view_id,
40+
bool CompositorSoftware::Present(FlutterWindowsView* view,
4241
const FlutterLayer** layers,
4342
size_t layers_count) {
44-
FlutterWindowsView* view = engine_->view(view_id);
45-
if (!view) {
46-
return false;
47-
}
43+
FML_DCHECK(view != nullptr);
4844

4945
// Clear the view if there are no layers to present.
5046
if (layers_count == 0) {

shell/platform/windows/compositor_software.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_SOFTWARE_H_
66
#define FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_SOFTWARE_H_
77

8+
#include "flutter/fml/macros.h"
89
#include "flutter/shell/platform/embedder/embedder.h"
910
#include "flutter/shell/platform/windows/compositor.h"
1011
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
@@ -15,7 +16,7 @@ namespace flutter {
1516
// rasterization and bitmaps.
1617
class CompositorSoftware : public Compositor {
1718
public:
18-
CompositorSoftware(FlutterWindowsEngine* engine);
19+
CompositorSoftware();
1920

2021
/// |Compositor|
2122
bool CreateBackingStore(const FlutterBackingStoreConfig& config,
@@ -24,12 +25,12 @@ class CompositorSoftware : public Compositor {
2425
bool CollectBackingStore(const FlutterBackingStore* store) override;
2526

2627
/// |Compositor|
27-
bool Present(FlutterViewId view_id,
28+
bool Present(FlutterWindowsView* view,
2829
const FlutterLayer** layers,
2930
size_t layers_count) override;
3031

3132
private:
32-
FlutterWindowsEngine* engine_;
33+
FML_DISALLOW_COPY_AND_ASSIGN(CompositorSoftware);
3334
};
3435

3536
} // namespace flutter

shell/platform/windows/compositor_software_unittests.cc

Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ class CompositorSoftwareTest : public WindowsTest {
4646
FlutterWindowsEngine* engine() { return engine_.get(); }
4747
MockFlutterWindowsView* view() { return view_.get(); }
4848

49-
void UseHeadlessEngine() {
50-
FlutterWindowsEngineBuilder builder{GetContext()};
51-
52-
engine_ = builder.Build();
53-
}
54-
5549
void UseEngineWithView() {
5650
FlutterWindowsEngineBuilder builder{GetContext()};
5751

@@ -62,9 +56,6 @@ class CompositorSoftwareTest : public WindowsTest {
6256
engine_ = builder.Build();
6357
view_ = std::make_unique<MockFlutterWindowsView>(engine_.get(),
6458
std::move(window));
65-
66-
EngineModifier modifier{engine_.get()};
67-
modifier.SetImplicitView(view_.get());
6859
}
6960

7061
private:
@@ -77,9 +68,7 @@ class CompositorSoftwareTest : public WindowsTest {
7768
} // namespace
7869

7970
TEST_F(CompositorSoftwareTest, CreateBackingStore) {
80-
UseHeadlessEngine();
81-
82-
auto compositor = CompositorSoftware{engine()};
71+
CompositorSoftware compositor;
8372

8473
FlutterBackingStoreConfig config = {};
8574
FlutterBackingStore backing_store = {};
@@ -91,7 +80,7 @@ TEST_F(CompositorSoftwareTest, CreateBackingStore) {
9180
TEST_F(CompositorSoftwareTest, Present) {
9281
UseEngineWithView();
9382

94-
auto compositor = CompositorSoftware{engine()};
83+
CompositorSoftware compositor;
9584

9685
FlutterBackingStoreConfig config = {};
9786
FlutterBackingStore backing_store = {};
@@ -104,62 +93,18 @@ TEST_F(CompositorSoftwareTest, Present) {
10493
const FlutterLayer* layer_ptr = &layer;
10594

10695
EXPECT_CALL(*view(), PresentSoftwareBitmap).WillOnce(Return(true));
107-
EXPECT_TRUE(compositor.Present(view()->view_id(), &layer_ptr, 1));
96+
EXPECT_TRUE(compositor.Present(view(), &layer_ptr, 1));
10897

10998
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
11099
}
111100

112101
TEST_F(CompositorSoftwareTest, PresentEmpty) {
113102
UseEngineWithView();
114103

115-
auto compositor = CompositorSoftware{engine()};
104+
CompositorSoftware compositor;
116105

117106
EXPECT_CALL(*view(), ClearSoftwareBitmap).WillOnce(Return(true));
118-
EXPECT_TRUE(compositor.Present(view()->view_id(), nullptr, 0));
119-
}
120-
121-
TEST_F(CompositorSoftwareTest, UnknownViewIgnored) {
122-
UseEngineWithView();
123-
124-
auto compositor = CompositorSoftware{engine()};
125-
126-
FlutterBackingStoreConfig config = {};
127-
FlutterBackingStore backing_store = {};
128-
129-
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
130-
131-
FlutterLayer layer = {};
132-
layer.type = kFlutterLayerContentTypeBackingStore;
133-
layer.backing_store = &backing_store;
134-
const FlutterLayer* layer_ptr = &layer;
135-
136-
FlutterViewId unknown_view_id = 123;
137-
ASSERT_NE(view()->view_id(), unknown_view_id);
138-
ASSERT_EQ(engine()->view(unknown_view_id), nullptr);
139-
140-
EXPECT_FALSE(compositor.Present(unknown_view_id, &layer_ptr, 1));
141-
142-
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
143-
}
144-
145-
TEST_F(CompositorSoftwareTest, HeadlessPresentIgnored) {
146-
UseHeadlessEngine();
147-
148-
auto compositor = CompositorSoftware{engine()};
149-
150-
FlutterBackingStoreConfig config = {};
151-
FlutterBackingStore backing_store = {};
152-
153-
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
154-
155-
FlutterLayer layer = {};
156-
layer.type = kFlutterLayerContentTypeBackingStore;
157-
layer.backing_store = &backing_store;
158-
const FlutterLayer* layer_ptr = &layer;
159-
160-
EXPECT_FALSE(compositor.Present(kImplicitViewId, &layer_ptr, 1));
161-
162-
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
107+
EXPECT_TRUE(compositor.Present(view(), nullptr, 0));
163108
}
164109

165110
} // namespace testing

shell/platform/windows/fixtures/main.dart

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,49 @@ void drawHelloWorld() {
315315
..addPicture(ui.Offset.zero, picture)
316316
..pop();
317317

318-
ui.window.render(sceneBuilder.build());
318+
ui.PlatformDispatcher.instance.implicitView?.render(sceneBuilder.build());
319319
};
320320

321321
ui.PlatformDispatcher.instance.scheduleFrame();
322322
notifyFirstFrameScheduled();
323323
}
324+
325+
ui.Picture _createColoredBox(ui.Color color, ui.Size size) {
326+
final ui.Paint paint = ui.Paint();
327+
paint.color = color;
328+
final ui.PictureRecorder baseRecorder = ui.PictureRecorder();
329+
final ui.Canvas canvas = ui.Canvas(baseRecorder);
330+
canvas.drawRect(ui.Rect.fromLTRB(0.0, 0.0, size.width, size.height), paint);
331+
return baseRecorder.endRecording();
332+
}
333+
334+
@pragma('vm:entry-point')
335+
void renderImplicitView() {
336+
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
337+
final ui.Size size = ui.Size(800.0, 600.0);
338+
final ui.Color red = ui.Color.fromARGB(127, 255, 0, 0);
339+
340+
final ui.SceneBuilder builder = ui.SceneBuilder();
341+
342+
builder.pushOffset(0.0, 0.0);
343+
344+
builder.addPicture(
345+
ui.Offset(0.0, 0.0), _createColoredBox(red, size));
346+
347+
builder.pop();
348+
349+
ui.PlatformDispatcher.instance.implicitView?.render(builder.build());
350+
};
351+
ui.PlatformDispatcher.instance.scheduleFrame();
352+
}
353+
354+
@pragma('vm:entry-point')
355+
void signalViewIds() {
356+
final Iterable<ui.FlutterView> views = ui.PlatformDispatcher.instance.views;
357+
final List<int> viewIds =
358+
views.map((ui.FlutterView view) => view.viewId).toList();
359+
360+
viewIds.sort();
361+
362+
signalStringValue('View IDs: [${viewIds.join(', ')}]');
363+
}

shell/platform/windows/flutter_windows_engine.cc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
393393
// constructors: https://github.com/flutter/flutter/issues/143375
394394
compositor_ = std::make_unique<CompositorOpenGL>(this, resolver);
395395
} else {
396-
compositor_ = std::make_unique<CompositorSoftware>(this);
396+
compositor_ = std::make_unique<CompositorSoftware>();
397397
}
398398

399399
FlutterCompositor compositor = {};
@@ -418,8 +418,7 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
418418
[](const FlutterPresentViewInfo* info) -> bool {
419419
auto host = static_cast<FlutterWindowsEngine*>(info->user_data);
420420

421-
return host->compositor_->Present(info->view_id, info->layers,
422-
info->layers_count);
421+
return host->Present(info);
423422
};
424423
args.compositor = &compositor;
425424

@@ -873,4 +872,15 @@ void FlutterWindowsEngine::OnChannelUpdate(std::string name, bool listening) {
873872
}
874873
}
875874

875+
bool FlutterWindowsEngine::Present(const FlutterPresentViewInfo* info) {
876+
auto iterator = views_.find(info->view_id);
877+
if (iterator == views_.end()) {
878+
return false;
879+
}
880+
881+
FlutterWindowsView* view = iterator->second;
882+
883+
return compositor_->Present(view, info->layers, info->layers_count);
884+
}
885+
876886
} // namespace flutter

0 commit comments

Comments
 (0)