Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions shell/platform/windows/flutter_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -372,18 +372,6 @@ ui::AXPlatformNodeWin* FlutterWindow::GetAlert() {
return alert_node_.get();
}

bool FlutterWindow::NeedsVSync() const {
// If the Desktop Window Manager composition is enabled,
// the system itself synchronizes with v-sync.
// See: https://learn.microsoft.com/windows/win32/dwm/composition-ovw
BOOL composition_enabled;
if (SUCCEEDED(::DwmIsCompositionEnabled(&composition_enabled))) {
return !composition_enabled;
}

return true;
}

void FlutterWindow::OnWindowStateEvent(WindowStateEvent event) {
switch (event) {
case WindowStateEvent::kShow:
Expand Down
3 changes: 0 additions & 3 deletions shell/platform/windows/flutter_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
// |WindowBindingHandler|
virtual ui::AXPlatformNodeWin* GetAlert() override;

// |WindowBindingHandler|
virtual bool NeedsVSync() const override;

// Called to obtain a pointer to the fragment root delegate.
virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate();

Expand Down
4 changes: 2 additions & 2 deletions shell/platform/windows/flutter_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(
width, height, engine_ptr->windows_proc_table());

auto engine = std::unique_ptr<flutter::FlutterWindowsEngine>(engine_ptr);
auto view =
std::make_unique<flutter::FlutterWindowsView>(std::move(window_wrapper));
auto view = std::make_unique<flutter::FlutterWindowsView>(
std::move(window_wrapper), engine_ptr->windows_proc_table());
auto controller = std::make_unique<flutter::FlutterWindowsViewController>(
std::move(engine), std::move(view));

Expand Down
27 changes: 19 additions & 8 deletions shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ bool SurfaceWillUpdate(size_t cur_width,

/// Update the surface's swap interval to block until the v-blank iff
/// the system compositor is disabled.
void UpdateVsync(const FlutterWindowsEngine& engine,
const WindowBindingHandler& window) {
void UpdateVsync(const FlutterWindowsEngine& engine, bool needs_vsync) {
AngleSurfaceManager* surface_manager = engine.surface_manager();
if (!surface_manager) {
return;
Expand All @@ -52,7 +51,6 @@ void UpdateVsync(const FlutterWindowsEngine& engine,
// the raster thread. If the engine is initializing, the raster thread doesn't
// exist yet and the render surface can be made current on the platform
// thread.
auto needs_vsync = window.NeedsVSync();
if (engine.running()) {
engine.PostRasterThreadTask([surface_manager, needs_vsync]() {
surface_manager->SetVSyncEnabled(needs_vsync);
Expand All @@ -72,7 +70,13 @@ void UpdateVsync(const FlutterWindowsEngine& engine,
} // namespace

FlutterWindowsView::FlutterWindowsView(
std::unique_ptr<WindowBindingHandler> window_binding) {
std::unique_ptr<WindowBindingHandler> window_binding,
std::shared_ptr<WindowsProcTable> windows_proc_table)
: windows_proc_table_(std::move(windows_proc_table)) {
if (windows_proc_table_ == nullptr) {
windows_proc_table_ = std::make_shared<WindowsProcTable>();
}

// Take the binding handler, and give it a pointer back to self.
binding_handler_ = std::move(window_binding);
binding_handler_->SetView(this);
Expand Down Expand Up @@ -114,7 +118,7 @@ void FlutterWindowsView::OnEmptyFrameGenerated() {
// resize_status_ is set to kDone.
engine_->surface_manager()->ResizeSurface(
GetWindowHandle(), resize_target_width_, resize_target_height_,
binding_handler_->NeedsVSync());
NeedsVsync());
resize_status_ = ResizeState::kFrameGenerated;
}

Expand All @@ -130,7 +134,7 @@ bool FlutterWindowsView::OnFrameGenerated(size_t width, size_t height) {
// Platform thread is blocked for the entire duration until the
// resize_status_ is set to kDone.
engine_->surface_manager()->ResizeSurface(GetWindowHandle(), width, height,
binding_handler_->NeedsVSync());
NeedsVsync());
resize_status_ = ResizeState::kFrameGenerated;
return true;
}
Expand Down Expand Up @@ -638,7 +642,7 @@ void FlutterWindowsView::CreateRenderSurface() {
engine_->surface_manager()->CreateSurface(GetWindowHandle(), bounds.width,
bounds.height);

UpdateVsync(*engine_, *binding_handler_);
UpdateVsync(*engine_, NeedsVsync());

resize_target_width_ = bounds.width;
resize_target_height_ = bounds.height;
Expand Down Expand Up @@ -706,7 +710,7 @@ void FlutterWindowsView::UpdateSemanticsEnabled(bool enabled) {
}

void FlutterWindowsView::OnDwmCompositionChanged() {
UpdateVsync(*engine_, *binding_handler_);
UpdateVsync(*engine_, NeedsVsync());
}

void FlutterWindowsView::OnWindowStateEvent(HWND hwnd, WindowStateEvent event) {
Expand All @@ -715,4 +719,11 @@ void FlutterWindowsView::OnWindowStateEvent(HWND hwnd, WindowStateEvent event) {
}
}

bool FlutterWindowsView::NeedsVsync() const {
// If the Desktop Window Manager composition is enabled,
// the system itself synchronizes with vsync.
// See: https://learn.microsoft.com/windows/win32/dwm/composition-ovw
return !windows_proc_table_->DwmIsCompositionEnabled();
}

} // namespace flutter
12 changes: 11 additions & 1 deletion shell/platform/windows/flutter_windows_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "flutter/shell/platform/windows/window_binding_handler.h"
#include "flutter/shell/platform/windows/window_binding_handler_delegate.h"
#include "flutter/shell/platform/windows/window_state.h"
#include "flutter/shell/platform/windows/windows_proc_table.h"

namespace flutter {

Expand All @@ -35,7 +36,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
//
// In order for object to render Flutter content the SetEngine method must be
// called with a valid FlutterWindowsEngine instance.
FlutterWindowsView(std::unique_ptr<WindowBindingHandler> window_binding);
FlutterWindowsView(
std::unique_ptr<WindowBindingHandler> window_binding,
std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr);

virtual ~FlutterWindowsView();

Expand Down Expand Up @@ -365,9 +368,16 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
void SendPointerEventWithData(const FlutterPointerEvent& event_data,
PointerState* state);

// If true, rendering to the window should synchronize with the vsync
// to prevent screen tearing.
bool NeedsVsync() const;

// The engine associated with this view.
FlutterWindowsEngine* engine_ = nullptr;

// Mocks win32 APIs.
std::shared_ptr<WindowsProcTable> windows_proc_table_;

// Keeps track of pointer states in relation to the window.
std::unordered_map<int32_t, std::unique_ptr<PointerState>> pointer_states_;

Expand Down
58 changes: 38 additions & 20 deletions shell/platform/windows/flutter_windows_view_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/mock_angle_surface_manager.h"
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
#include "flutter/shell/platform/windows/testing/test_keyboard.h"

#include "gmock/gmock.h"
Expand Down Expand Up @@ -814,18 +815,20 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) {

auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*window_binding_handler.get(), NeedsVSync)
.WillOnce(Return(false));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(true));
EXPECT_CALL(
*surface_manager.get(),
ResizeSurface(_, /*width=*/500, /*height=*/500, /*enable_vsync=*/false))
.Times(1);
EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);

FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));
modifier.SetSurfaceManager(std::move(surface_manager));
view.SetEngine(engine.get());

Expand Down Expand Up @@ -861,18 +864,20 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {

auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*window_binding_handler.get(), NeedsVSync)
.WillOnce(Return(false));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(true));
EXPECT_CALL(
*surface_manager.get(),
ResizeSurface(_, /*width=*/500, /*height=*/500, /*enable_vsync=*/false))
.Times(1);
EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);

FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));
modifier.SetSurfaceManager(std::move(surface_manager));
view.SetEngine(engine.get());

Expand Down Expand Up @@ -1254,17 +1259,19 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
std::make_unique<MockFlutterWindowsEngine>();
auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(false));
EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);

EXPECT_CALL(*window_binding_handler.get(), NeedsVSync)
.WillOnce(Return(false));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(true));

EngineModifier modifier(engine.get());
FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));

InSequence s;
EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
Expand All @@ -1289,15 +1296,18 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
std::make_unique<MockFlutterWindowsEngine>();
auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(false));
EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
EXPECT_CALL(*window_binding_handler.get(), NeedsVSync).WillOnce(Return(true));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(false));

EngineModifier modifier(engine.get());
FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));

InSequence s;
EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
Expand All @@ -1322,14 +1332,17 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
std::make_unique<MockFlutterWindowsEngine>();
auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(true));
EXPECT_CALL(*window_binding_handler.get(), NeedsVSync).WillOnce(Return(true));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(true));

EngineModifier modifier(engine.get());
FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));

InSequence s;
EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
Expand All @@ -1340,7 +1353,7 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
callback();
return true;
});
EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(true)).Times(1);
EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(false)).Times(1);
EXPECT_CALL(*surface_manager.get(), ClearCurrent).Times(0);

EXPECT_CALL(*engine.get(), Stop).Times(1);
Expand All @@ -1359,15 +1372,18 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
std::make_unique<MockFlutterWindowsEngine>();
auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(true));

EXPECT_CALL(*window_binding_handler.get(), NeedsVSync).WillOnce(Return(true));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(false));

EngineModifier modifier(engine.get());
FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));

InSequence s;
EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
Expand Down Expand Up @@ -1398,6 +1414,7 @@ TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
std::make_unique<MockFlutterWindowsEngine>();
auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
std::unique_ptr<MockAngleSurfaceManager> surface_manager =
std::make_unique<MockAngleSurfaceManager>();

Expand All @@ -1409,14 +1426,15 @@ TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
return true;
});

EXPECT_CALL(*window_binding_handler.get(), NeedsVSync)
.WillOnce(Return(true))
.WillOnce(Return(false));
EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
.WillOnce(Return(false))
.WillOnce(Return(true));

EXPECT_CALL(*surface_manager.get(), ClearCurrent).Times(0);

EngineModifier modifier(engine.get());
FlutterWindowsView view(std::move(window_binding_handler));
FlutterWindowsView view(std::move(window_binding_handler),
std::move(windows_proc_table));

InSequence s;
EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(true)).Times(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class MockWindowBindingHandler : public WindowBindingHandler {
MOCK_METHOD(PointerLocation, GetPrimaryPointerLocation, (), (override));
MOCK_METHOD(AlertPlatformNodeDelegate*, GetAlertDelegate, (), (override));
MOCK_METHOD(ui::AXPlatformNodeWin*, GetAlert, (), (override));
MOCK_METHOD(bool, NeedsVSync, (), (const override));

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowBindingHandler);
Expand Down
6 changes: 4 additions & 2 deletions shell/platform/windows/testing/mock_windows_proc_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ class MockWindowsProcTable : public WindowsProcTable {
MOCK_METHOD(BOOL,
GetPointerType,
(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type),
(override));
(const, override));

MOCK_METHOD(LRESULT,
GetThreadPreferredUILanguages,
(DWORD, PULONG, PZZWSTR, PULONG),
(const, override));

MOCK_METHOD(bool, GetHighContrastEnabled, (), (override));
MOCK_METHOD(bool, GetHighContrastEnabled, (), (const, override));

MOCK_METHOD(bool, DwmIsCompositionEnabled, (), (const, override));

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable);
Expand Down
4 changes: 0 additions & 4 deletions shell/platform/windows/window_binding_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ class WindowBindingHandler {

// Retrieve the alert node.
virtual ui::AXPlatformNodeWin* GetAlert() = 0;

// If true, rendering to the window should synchronize with the vsync
// to prevent screen tearing.
virtual bool NeedsVSync() const = 0;
};

} // namespace flutter
Expand Down
Loading