Skip to content

Commit

Permalink
[Windows] Move to FlutterCompositor for rendering (#48849)
Browse files Browse the repository at this point in the history
This migrates the Windows embedder to `FlutterCompositor` so that the engine renders off-screen to a framebuffer instead of directly onto the window's surface. This will allow us to support platform views and multiple views on Windows.

<details>
<summary>Tests...</summary>

* Verify OpenGL compositor's raster time isn't regressed and memory increase is reasonable
* Software compositor's raster time and memory isn't regressed

Test device configurations
* [x] Windows 11 (hardware acceleration enabled/disabled)
* [x] Windows Arm64 (hardware acceleration enabled/disabled)
* [x] Windows 7 (hardware acceleration enabled/disabled, DWM enabled/disabled)

</details>

Addresses flutter/flutter#128904

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
loic-sharma authored Dec 13, 2023
1 parent 9f7004e commit 45b95f2
Show file tree
Hide file tree
Showing 16 changed files with 753 additions and 29 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@
../../../flutter/shell/platform/windows/client_wrapper/flutter_view_unittests.cc
../../../flutter/shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc
../../../flutter/shell/platform/windows/client_wrapper/testing
../../../flutter/shell/platform/windows/compositor_opengl_unittests.cc
../../../flutter/shell/platform/windows/compositor_software_unittests.cc
../../../flutter/shell/platform/windows/cursor_handler_unittests.cc
../../../flutter/shell/platform/windows/direct_manipulation_unittests.cc
../../../flutter/shell/platform/windows/dpi_utils_unittests.cc
Expand Down
10 changes: 10 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -7113,6 +7113,11 @@ ORIGIN: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/f
ORIGIN: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/compositor.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/compositor_opengl.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/compositor_opengl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/compositor_software.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/compositor_software.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/cursor_handler.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/cursor_handler.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/direct_manipulation.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -9942,6 +9947,11 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h
FILE: ../../../flutter/shell/platform/windows/compositor.h
FILE: ../../../flutter/shell/platform/windows/compositor_opengl.cc
FILE: ../../../flutter/shell/platform/windows/compositor_opengl.h
FILE: ../../../flutter/shell/platform/windows/compositor_software.cc
FILE: ../../../flutter/shell/platform/windows/compositor_software.h
FILE: ../../../flutter/shell/platform/windows/cursor_handler.cc
FILE: ../../../flutter/shell/platform/windows/cursor_handler.h
FILE: ../../../flutter/shell/platform/windows/direct_manipulation.cc
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/gles/description_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ std::string DescriptionGLES::GetString() const {
return stream.str();
}

Version DescriptionGLES::GetGlVersion() const {
return gl_version_;
}

bool DescriptionGLES::IsES() const {
return is_es_;
}
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/gles/description_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class DescriptionGLES {

std::string GetString() const;

Version GetGlVersion() const;

bool HasExtension(const std::string& ext) const;

/// @brief Returns whether GLES includes the debug extension.
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/linux/fl_backing_store_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ uint32_t fl_backing_store_provider_get_gl_format(FlBackingStoreProvider* self) {
// In Linux kN32_SkColorType is assumed to be kBGRA_8888_SkColorType.
// So we must choose a valid gl format to be compatible with surface format
// BGRA8.
// Following logics are copied from Skia GrGLCaps.cpp.
// Following logics are copied from Skia GrGLCaps.cpp:
// https://github.com/google/skia/blob/4738ed711e03212aceec3cd502a4adb545f38e63/src/gpu/ganesh/gl/GrGLCaps.cpp#L1963-L2116

if (epoxy_is_desktop_gl()) {
// For OpenGL.
Expand Down
9 changes: 9 additions & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ source_set("flutter_windows_source") {
"accessibility_bridge_windows.h",
"angle_surface_manager.cc",
"angle_surface_manager.h",
"compositor.h",
"compositor_opengl.cc",
"compositor_opengl.h",
"compositor_software.cc",
"compositor_software.h",
"cursor_handler.cc",
"cursor_handler.h",
"direct_manipulation.cc",
Expand Down Expand Up @@ -134,6 +139,7 @@ source_set("flutter_windows_source") {
deps = [
":flutter_windows_headers",
"//flutter/fml:fml",
"//flutter/impeller/renderer/backend/gles",
"//flutter/shell/platform/common:common_cpp",
"//flutter/shell/platform/common:common_cpp_input",
"//flutter/shell/platform/common:common_cpp_switches",
Expand Down Expand Up @@ -175,6 +181,8 @@ executable("flutter_windows_unittests") {
# Common Windows test sources.
sources = [
"accessibility_bridge_windows_unittests.cc",
"compositor_opengl_unittests.cc",
"compositor_software_unittests.cc",
"cursor_handler_unittests.cc",
"direct_manipulation_unittests.cc",
"dpi_utils_unittests.cc",
Expand Down Expand Up @@ -235,6 +243,7 @@ executable("flutter_windows_unittests") {
":flutter_windows_fixtures",
":flutter_windows_headers",
":flutter_windows_source",
"//flutter/impeller/renderer/backend/gles",
"//flutter/shell/platform/common:common_cpp",
"//flutter/shell/platform/common/client_wrapper:client_wrapper",
"//flutter/shell/platform/embedder:embedder_as_internal_library",
Expand Down
39 changes: 39 additions & 0 deletions shell/platform/windows/compositor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_H_

#include "flutter/shell/platform/embedder/embedder.h"

namespace flutter {

// Enables the Flutter engine to render content on Windows.
//
// The engine uses this to:
//
// 1. Create backing stores used for rendering Flutter content
// 2. Composite and present Flutter content and platform views onto a view
//
// Platform views are not yet supported.
class Compositor {
public:
virtual ~Compositor() = default;

// Create a backing store used for rendering Flutter content.
//
// The backing store's configuration is stored in |backing_store_out|.
virtual bool CreateBackingStore(const FlutterBackingStoreConfig& config,
FlutterBackingStore* backing_store_out) = 0;

// Destroys a backing store and releases its resources.
virtual bool CollectBackingStore(const FlutterBackingStore* store) = 0;

// Present Flutter content and platform views onto the view.
virtual bool Present(const FlutterLayer** layers, size_t layers_count) = 0;
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_H_
154 changes: 154 additions & 0 deletions shell/platform/windows/compositor_opengl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/windows/compositor_opengl.h"

#include "GLES3/gl3.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"

namespace flutter {

namespace {

// The metadata for an OpenGL framebuffer backing store.
struct FramebufferBackingStore {
uint32_t framebuffer_id;
uint32_t texture_id;
};

// Based off Skia's logic:
// https://github.com/google/skia/blob/4738ed711e03212aceec3cd502a4adb545f38e63/src/gpu/ganesh/gl/GrGLCaps.cpp#L1963-L2116
int GetSupportedTextureFormat(const impeller::DescriptionGLES* description) {
if (description->HasExtension("GL_EXT_texture_format_BGRA8888")) {
return GL_BGRA8_EXT;
} else if (description->HasExtension("GL_APPLE_texture_format_BGRA8888") &&
description->GetGlVersion().IsAtLeast(impeller::Version(3, 0))) {
return GL_BGRA8_EXT;
} else {
return GL_RGBA8;
}
}

} // namespace

CompositorOpenGL::CompositorOpenGL(FlutterWindowsEngine* engine,
impeller::ProcTableGLES::Resolver resolver)
: engine_(engine), resolver_(resolver) {}

bool CompositorOpenGL::CreateBackingStore(
const FlutterBackingStoreConfig& config,
FlutterBackingStore* result) {
if (!is_initialized_ && !Initialize()) {
return false;
}

auto store = std::make_unique<FramebufferBackingStore>();

gl_->GenTextures(1, &store->texture_id);
gl_->GenFramebuffers(1, &store->framebuffer_id);

gl_->BindFramebuffer(GL_FRAMEBUFFER, store->framebuffer_id);

gl_->BindTexture(GL_TEXTURE_2D, store->texture_id);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, config.size.width,
config.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
gl_->BindTexture(GL_TEXTURE_2D, 0);

gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, store->texture_id, 0);

result->type = kFlutterBackingStoreTypeOpenGL;
result->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
result->open_gl.framebuffer.name = store->framebuffer_id;
result->open_gl.framebuffer.target = format_;
result->open_gl.framebuffer.user_data = store.release();
result->open_gl.framebuffer.destruction_callback = [](void* user_data) {
// Backing store destroyed in `CompositorOpenGL::CollectBackingStore`, set
// on FlutterCompositor.collect_backing_store_callback during engine start.
};
return true;
}

bool CompositorOpenGL::CollectBackingStore(const FlutterBackingStore* store) {
FML_DCHECK(is_initialized_);
FML_DCHECK(store->type == kFlutterBackingStoreTypeOpenGL);
FML_DCHECK(store->open_gl.type == kFlutterOpenGLTargetTypeFramebuffer);

auto user_data = static_cast<FramebufferBackingStore*>(
store->open_gl.framebuffer.user_data);

gl_->DeleteFramebuffers(1, &user_data->framebuffer_id);
gl_->DeleteTextures(1, &user_data->texture_id);

delete user_data;
return true;
}

bool CompositorOpenGL::Present(const FlutterLayer** layers,
size_t layers_count) {
// TODO: Support compositing layers and platform views.
// See: https://github.com/flutter/flutter/issues/31713
FML_DCHECK(is_initialized_);
FML_DCHECK(layers_count == 1);
FML_DCHECK(layers[0]->type == kFlutterLayerContentTypeBackingStore);
FML_DCHECK(layers[0]->backing_store->type == kFlutterBackingStoreTypeOpenGL);
FML_DCHECK(layers[0]->backing_store->open_gl.type ==
kFlutterOpenGLTargetTypeFramebuffer);

if (!engine_->view()) {
return false;
}

auto width = layers[0]->size.width;
auto height = layers[0]->size.height;

// Acquiring the view's framebuffer ID resizes its surface if necessary.
auto destination_id = engine_->view()->GetFrameBufferId(width, height);
auto source_id = layers[0]->backing_store->open_gl.framebuffer.name;

if (!engine_->surface_manager()->MakeCurrent()) {
return false;
}

gl_->BindFramebuffer(GL_READ_FRAMEBUFFER, source_id);
gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, destination_id);

gl_->BlitFramebuffer(0, // srcX0
0, // srcY0
width, // srcX1
height, // srcY1
0, // dstX0
0, // dstY0
width, // dstX1
height, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_NEAREST // filter
);

return engine_->view()->SwapBuffers();
}

bool CompositorOpenGL::Initialize() {
FML_DCHECK(!is_initialized_);

if (!engine_->surface_manager()->MakeCurrent()) {
return false;
}

gl_ = std::make_unique<impeller::ProcTableGLES>(resolver_);
if (!gl_->IsValid()) {
gl_.reset();
return false;
}

format_ = GetSupportedTextureFormat(gl_->GetDescription());
is_initialized_ = true;
return true;
}

} // namespace flutter
58 changes: 58 additions & 0 deletions shell/platform/windows/compositor_opengl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_OPENGL_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_OPENGL_H_

#include <memory>

#include "flutter/impeller/renderer/backend/gles/proc_table_gles.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/compositor.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"

namespace flutter {

// Enables the Flutter engine to render content on Windows using OpenGL.
class CompositorOpenGL : public Compositor {
public:
CompositorOpenGL(FlutterWindowsEngine* engine,
impeller::ProcTableGLES::Resolver resolver);

/// |Compositor|
bool CreateBackingStore(const FlutterBackingStoreConfig& config,
FlutterBackingStore* result) override;

/// |Compositor|
bool CollectBackingStore(const FlutterBackingStore* store) override;

/// |Compositor|
bool Present(const FlutterLayer** layers, size_t layers_count) override;

private:
// The Flutter engine that manages the views to render.
FlutterWindowsEngine* engine_;

private:
// The compositor initializes itself lazily once |CreateBackingStore| is
// called. True if initialization completed successfully.
bool is_initialized_ = false;

// Function used to resolve GLES functions.
impeller::ProcTableGLES::Resolver resolver_ = nullptr;

// Table of resolved GLES functions. Null until the compositor is initialized.
std::unique_ptr<impeller::ProcTableGLES> gl_ = nullptr;

// The OpenGL texture target format for backing stores. Invalid value until
// the compositor is initialized.
uint32_t format_ = 0;

// Initialize the compositor. This must run on the raster thread.
bool Initialize();
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_COMPOSITOR_OPENGL_H_
Loading

0 comments on commit 45b95f2

Please sign in to comment.