Fix flutter#40068 Redraw issues on resize/minimize/maximize on Windows and startup in release (#20357)
* Fix redraw issues
* Address CR feedback.
* Fix build
* CR feedback
diff --git a/shell/platform/windows/angle_surface_manager.cc b/shell/platform/windows/angle_surface_manager.cc
index cc04628..eda082c 100644
--- a/shell/platform/windows/angle_surface_manager.cc
+++ b/shell/platform/windows/angle_surface_manager.cc
@@ -169,14 +169,22 @@
}
}
-bool AngleSurfaceManager::CreateSurface(WindowsRenderTarget* render_target) {
+bool AngleSurfaceManager::CreateSurface(WindowsRenderTarget* render_target,
+ EGLint width,
+ EGLint height) {
if (!render_target || !initialize_succeeded_) {
return false;
}
EGLSurface surface = EGL_NO_SURFACE;
- const EGLint surfaceAttributes[] = {EGL_NONE};
+ // Disable Angle's automatic surface sizing logic and provide and exlicit
+ // size. AngleSurfaceManager is responsible for initiating Angle surface size
+ // changes to avoid race conditions with rendering when automatic mode is
+ // used.
+ const EGLint surfaceAttributes[] = {
+ EGL_FIXED_SIZE_ANGLE, EGL_TRUE, EGL_WIDTH, width,
+ EGL_HEIGHT, height, EGL_NONE};
surface = eglCreateWindowSurface(
egl_display_, egl_config_,
@@ -190,6 +198,26 @@
return true;
}
+void AngleSurfaceManager::ResizeSurface(WindowsRenderTarget* render_target,
+ EGLint width,
+ EGLint height) {
+ EGLint existing_width, existing_height;
+ GetSurfaceDimensions(&existing_width, &existing_height);
+ if (width != existing_width || height != existing_height) {
+ // Destroy existing surface with previous stale dimensions and create new
+ // surface at new size. Since the Windows compositor retains the front
+ // buffer until the new surface has been presented, no need to manually
+ // preserve the previous surface contents. This resize approach could be
+ // further optimized if Angle exposed a public entrypoint for
+ // SwapChain11::reset or SwapChain11::resize.
+ DestroySurface();
+ if (!CreateSurface(render_target, width, height)) {
+ std::cerr << "AngleSurfaceManager::ResizeSurface failed to create surface"
+ << std::endl;
+ }
+ }
+}
+
void AngleSurfaceManager::GetSurfaceDimensions(EGLint* width, EGLint* height) {
if (render_surface_ == EGL_NO_SURFACE || !initialize_succeeded_) {
width = 0;
diff --git a/shell/platform/windows/angle_surface_manager.h b/shell/platform/windows/angle_surface_manager.h
index a6a5fc2..60754c3 100644
--- a/shell/platform/windows/angle_surface_manager.h
+++ b/shell/platform/windows/angle_surface_manager.h
@@ -23,6 +23,8 @@
// destroy surfaces
class AngleSurfaceManager {
public:
+ // Creates a new surface manager retaining reference to the passed-in target
+ // for the lifetime of the manager.
AngleSurfaceManager();
~AngleSurfaceManager();
@@ -32,8 +34,19 @@
// Creates an EGLSurface wrapper and backing DirectX 11 SwapChain
// asociated with window, in the appropriate format for display.
- // Target represents the visual entity to bind to.
- bool CreateSurface(WindowsRenderTarget* render_target);
+ // Target represents the visual entity to bind to. Width and
+ // height represent dimensions surface is created at.
+ bool CreateSurface(WindowsRenderTarget* render_target,
+ EGLint width,
+ EGLint height);
+
+ // Resizes backing surface from current size to newly requested size
+ // based on width and height for the specific case when width and height do
+ // not match current surface dimensions. Target represents the visual entity
+ // to bind to.
+ void ResizeSurface(WindowsRenderTarget* render_target,
+ EGLint width,
+ EGLint height);
// queries EGL for the dimensions of surface in physical
// pixels returning width and height as out params.
diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc
index f35a4c1..1e997da 100644
--- a/shell/platform/windows/flutter_windows.cc
+++ b/shell/platform/windows/flutter_windows.cc
@@ -65,6 +65,9 @@
return nullptr;
}
}
+
+ // Must happen after engine is running.
+ state->view->SendInitialBounds();
return state.release();
}
diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc
index 9c463c3..5736ce9 100644
--- a/shell/platform/windows/flutter_windows_view.cc
+++ b/shell/platform/windows/flutter_windows_view.cc
@@ -52,6 +52,7 @@
void FlutterWindowsView::OnWindowSizeChanged(size_t width,
size_t height) const {
+ surface_manager_->ResizeSurface(GetRenderTarget(), width, height);
SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
}
@@ -127,6 +128,13 @@
auto result = FlutterEngineSendWindowMetricsEvent(engine_->engine(), &event);
}
+void FlutterWindowsView::SendInitialBounds() {
+ PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
+
+ SendWindowMetrics(bounds.width, bounds.height,
+ binding_handler_->GetDpiScale());
+}
+
// Set's |event_data|'s phase to either kMove or kHover depending on the current
// primary mouse button state.
void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
@@ -263,7 +271,9 @@
}
void FlutterWindowsView::CreateRenderSurface() {
- surface_manager_->CreateSurface(render_target_.get());
+ PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
+ surface_manager_->CreateSurface(GetRenderTarget(), bounds.width,
+ bounds.height);
}
void FlutterWindowsView::DestroyRenderSurface() {
@@ -272,7 +282,7 @@
}
}
-WindowsRenderTarget* FlutterWindowsView::GetRenderTarget() {
+WindowsRenderTarget* FlutterWindowsView::GetRenderTarget() const {
return render_target_.get();
}
diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h
index 13ff056..5df86e4 100644
--- a/shell/platform/windows/flutter_windows_view.h
+++ b/shell/platform/windows/flutter_windows_view.h
@@ -52,7 +52,7 @@
void DestroyRenderSurface();
// Return the currently configured WindowsRenderTarget.
- WindowsRenderTarget* GetRenderTarget();
+ WindowsRenderTarget* GetRenderTarget() const;
// Returns the engine backing this view.
FlutterWindowsEngine* GetEngine();
@@ -63,6 +63,9 @@
bool MakeResourceCurrent();
bool SwapBuffers();
+ // Send initial bounds to embedder. Must occur after engine has initialized.
+ void SendInitialBounds();
+
// |WindowBindingHandlerDelegate|
void OnWindowSizeChanged(size_t width, size_t height) const override;