未验证 提交 f6162dc7 编写于 作者: K Kaushik Iska 提交者: GitHub

[windows] Enable smooth resizing on windows (#23701)

上级 eb031d35
......@@ -102,6 +102,8 @@ source_set("flutter_windows_source") {
"win32_window_proc_delegate_manager.cc",
"win32_window_proc_delegate_manager.h",
]
libs = [ "dwmapi.lib" ]
}
configs += [
......
......@@ -50,7 +50,17 @@ FlutterRendererConfig GetRendererConfig() {
}
return host->view()->SwapBuffers();
};
config.open_gl.fbo_callback = [](void* user_data) -> uint32_t { return 0; };
config.open_gl.fbo_reset_after_present = true;
config.open_gl.fbo_with_frame_info_callback =
[](void* user_data, const FlutterFrameInfo* info) -> uint32_t {
auto host = static_cast<FlutterWindowsEngine*>(user_data);
if (host->view()) {
return host->view()->GetFrameBufferId(info->size.width,
info->size.height);
} else {
return kWindowFrameBufferID;
}
};
config.open_gl.gl_proc_resolver = [](void* user_data,
const char* what) -> void* {
return reinterpret_cast<void*>(eglGetProcAddress(what));
......
......@@ -49,10 +49,41 @@ void FlutterWindowsView::SetEngine(
binding_handler_->GetDpiScale());
}
void FlutterWindowsView::OnWindowSizeChanged(size_t width,
size_t height) const {
surface_manager_->ResizeSurface(GetRenderTarget(), width, height);
uint32_t FlutterWindowsView::GetFrameBufferId(size_t width, size_t height) {
// Called on an engine-controlled (non-platform) thread.
std::unique_lock<std::mutex> lock(resize_mutex_);
if (resize_status_ != ResizeState::kResizeStarted) {
return kWindowFrameBufferID;
}
if (resize_target_width_ == width && resize_target_height_ == height) {
// Platform thread is blocked for the entire duration until the
// resize_status_ is set to kDone.
surface_manager_->ResizeSurface(GetRenderTarget(), width, height);
surface_manager_->MakeCurrent();
resize_status_ = ResizeState::kFrameGenerated;
}
return kWindowFrameBufferID;
}
void FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) {
// Called on the platform thread.
std::unique_lock<std::mutex> lock(resize_mutex_);
resize_status_ = ResizeState::kResizeStarted;
resize_target_width_ = width;
resize_target_height_ = height;
SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
if (width > 0 && height > 0) {
// Block the platform thread until:
// 1. GetFrameBufferId is called with the right frame size.
// 2. Any pending SwapBuffers calls have been invoked.
resize_cv_.wait(lock, [&resize_status = resize_status_] {
return resize_status == ResizeState::kDone;
});
}
}
void FlutterWindowsView::OnPointerMove(double x, double y) {
......@@ -255,7 +286,27 @@ bool FlutterWindowsView::ClearContext() {
}
bool FlutterWindowsView::SwapBuffers() {
return surface_manager_->SwapBuffers();
// Called on an engine-controlled (non-platform) thread.
std::unique_lock<std::mutex> lock(resize_mutex_);
switch (resize_status_) {
// SwapBuffer requests during resize are ignored until the frame with the
// right dimensions has been generated. This is marked with
// kFrameGenerated resize status.
case ResizeState::kResizeStarted:
return false;
case ResizeState::kFrameGenerated: {
bool swap_buffers_result = surface_manager_->SwapBuffers();
resize_status_ = ResizeState::kDone;
lock.unlock();
resize_cv_.notify_all();
binding_handler_->OnWindowResized();
return swap_buffers_result;
}
case ResizeState::kDone:
default:
return surface_manager_->SwapBuffers();
}
}
void FlutterWindowsView::CreateRenderSurface() {
......
......@@ -8,6 +8,7 @@
#include <windowsx.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
......@@ -27,6 +28,9 @@
namespace flutter {
// ID for the window frame buffer.
inline constexpr uint32_t kWindowFrameBufferID = 0;
// An OS-windowing neutral abstration for flutter
// view that works with win32 hwnds and Windows::UI::Composition visuals.
class FlutterWindowsView : public WindowBindingHandlerDelegate {
......@@ -57,7 +61,8 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
// Returns the engine backing this view.
FlutterWindowsEngine* GetEngine();
// Callbacks for clearing context, settings context and swapping buffers.
// Callbacks for clearing context, settings context and swapping buffers,
// these are typically called on an engine-controlled (non-platform) thread.
bool ClearContext();
bool MakeCurrent();
bool MakeResourceCurrent();
......@@ -66,8 +71,11 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
// Send initial bounds to embedder. Must occur after engine has initialized.
void SendInitialBounds();
// Returns the frame buffer id for the engine to render to.
uint32_t GetFrameBufferId(size_t width, size_t height);
// |WindowBindingHandlerDelegate|
void OnWindowSizeChanged(size_t width, size_t height) const override;
void OnWindowSizeChanged(size_t width, size_t height) override;
// |WindowBindingHandlerDelegate|
void OnPointerMove(double x, double y) override;
......@@ -115,6 +123,19 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
uint64_t buttons = 0;
};
// States a resize event can be in.
enum class ResizeState {
// When a resize event has started but is in progress.
kResizeStarted,
// After a resize event starts and the framework has been notified to
// generate a frame for the right size.
kFrameGenerated,
// Default state for when no resize is in progress. Also used to indicate
// that during a resize event, a frame with the right size has been rendered
// and the buffers have been swapped.
kDone,
};
// Sends a window metrics update to the Flutter engine using current window
// dimensions in physical
void SendWindowMetrics(size_t width, size_t height, double dpiscale) const;
......@@ -206,6 +227,23 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
// Currently configured WindowBindingHandler for view.
std::unique_ptr<flutter::WindowBindingHandler> binding_handler_;
// Resize events are synchronized using this mutex and the corresponding
// condition variable.
std::mutex resize_mutex_;
std::condition_variable resize_cv_;
// Indicates the state of a window resize event. Platform thread will be
// blocked while this is not done. Guarded by resize_mutex_.
ResizeState resize_status_ = ResizeState::kDone;
// Target for the window width. Valid when resize_pending_ is set. Guarded by
// resize_mutex_.
size_t resize_target_width_ = 0;
// Target for the window width. Valid when resize_pending_ is set. Guarded by
// resize_mutex_.
size_t resize_target_height_ = 0;
};
} // namespace flutter
......
......@@ -4,6 +4,7 @@
#include "flutter/shell/platform/windows/win32_flutter_window.h"
#include <dwmapi.h>
#include <chrono>
#include <map>
......@@ -92,6 +93,12 @@ void Win32FlutterWindow::UpdateFlutterCursor(const std::string& cursor_name) {
current_cursor_ = GetCursorByName(cursor_name);
}
void Win32FlutterWindow::OnWindowResized() {
// Blocking the raster thread until DWM flushes alleviates glitches where
// previous size surface is stretched over current size view.
DwmFlush();
}
// Translates button codes from Win32 API to FlutterPointerMouseButtons.
static uint64_t ConvertWinButtonToFlutterButton(UINT button) {
switch (button) {
......
......@@ -74,6 +74,9 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler {
// |FlutterWindowBindingHandler|
void UpdateFlutterCursor(const std::string& cursor_name) override;
// |FlutterWindowBindingHandler|
void OnWindowResized() override;
private:
// A pointer to a FlutterWindowsView that can be used to update engine
// windowing and input state.
......
......@@ -45,6 +45,9 @@ class WindowBindingHandler {
// Returns the bounds of the backing window in physical pixels.
virtual PhysicalWindowBounds GetPhysicalWindowBounds() = 0;
// Invoked after the window has been resized.
virtual void OnWindowResized() = 0;
// Sets the cursor that should be used when the mouse is over the Flutter
// content. See mouse_cursor.dart for the values and meanings of cursor_name.
virtual void UpdateFlutterCursor(const std::string& cursor_name) = 0;
......
......@@ -12,8 +12,9 @@ namespace flutter {
class WindowBindingHandlerDelegate {
public:
// Notifies delegate that backing window size has changed.
// Typically called by currently configured WindowBindingHandler
virtual void OnWindowSizeChanged(size_t width, size_t height) const = 0;
// Typically called by currently configured WindowBindingHandler, this is
// called on the platform thread.
virtual void OnWindowSizeChanged(size_t width, size_t height) = 0;
// Notifies delegate that backing window mouse has moved.
// Typically called by currently configured WindowBindingHandler
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册