diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index dc61d43393e8c..77950a37eaae8 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1038,6 +1038,23 @@ static sk_sp MakeSkSurfaceFromBackingStore( #endif } +#if defined(SHELL_ENABLE_GL) && defined(IMPELLER_SUPPORTS_RENDERING) +static std::optional FlutterFormatToImpellerPixelFormat( + uint32_t format) { + switch (format) { + case GL_BGRA8_EXT: + return impeller::PixelFormat::kB8G8R8A8UNormInt; + case GL_RGBA8: + return impeller::PixelFormat::kR8G8B8A8UNormInt; + default: + FML_LOG(ERROR) << "Cannot convert format " << format + << " to impeller::PixelFormat."; + return std::nullopt; + } +} + +#endif // defined(SHELL_ENABLE_GL) && defined(IMPELLER_SUPPORTS_RENDERING) + static std::unique_ptr MakeRenderTargetFromBackingStoreImpeller( FlutterBackingStore backing_store, @@ -1046,18 +1063,30 @@ MakeRenderTargetFromBackingStoreImpeller( const FlutterBackingStoreConfig& config, const FlutterOpenGLFramebuffer* framebuffer) { #if defined(SHELL_ENABLE_GL) && defined(IMPELLER_SUPPORTS_RENDERING) + auto format = FlutterFormatToImpellerPixelFormat(framebuffer->target); + if (!format.has_value()) { + return nullptr; + } const auto& gl_context = impeller::ContextGLES::Cast(*aiks_context->GetContext()); + const bool implicit_msaa = aiks_context->GetContext() + ->GetCapabilities() + ->SupportsImplicitResolvingMSAA(); const auto size = impeller::ISize(config.size.width, config.size.height); impeller::TextureDescriptor color0_tex; - color0_tex.type = impeller::TextureType::kTexture2D; - color0_tex.format = impeller::PixelFormat::kR8G8B8A8UNormInt; + if (implicit_msaa) { + color0_tex.type = impeller::TextureType::kTexture2DMultisample; + color0_tex.sample_count = impeller::SampleCount::kCount4; + } else { + color0_tex.type = impeller::TextureType::kTexture2D; + color0_tex.sample_count = impeller::SampleCount::kCount1; + } + color0_tex.format = format.value(); color0_tex.size = size; color0_tex.usage = static_cast( impeller::TextureUsage::kRenderTarget); - color0_tex.sample_count = impeller::SampleCount::kCount1; color0_tex.storage_mode = impeller::StorageMode::kDevicePrivate; impeller::ColorAttachment color0; @@ -1065,15 +1094,25 @@ MakeRenderTargetFromBackingStoreImpeller( gl_context.GetReactor(), color0_tex, framebuffer->name); color0.clear_color = impeller::Color::DarkSlateGray(); color0.load_action = impeller::LoadAction::kClear; - color0.store_action = impeller::StoreAction::kStore; + if (implicit_msaa) { + color0.store_action = impeller::StoreAction::kMultisampleResolve; + color0.resolve_texture = color0.texture; + } else { + color0.store_action = impeller::StoreAction::kStore; + } impeller::TextureDescriptor depth_stencil_texture_desc; - depth_stencil_texture_desc.type = impeller::TextureType::kTexture2D; - depth_stencil_texture_desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt; + depth_stencil_texture_desc.type = + impeller::TextureType::kTexture2DMultisample; + depth_stencil_texture_desc.format = impeller::PixelFormat::kD24UnormS8Uint; depth_stencil_texture_desc.size = size; depth_stencil_texture_desc.usage = static_cast( impeller::TextureUsage::kRenderTarget); - depth_stencil_texture_desc.sample_count = impeller::SampleCount::kCount1; + if (implicit_msaa) { + depth_stencil_texture_desc.sample_count = impeller::SampleCount::kCount4; + } else { + depth_stencil_texture_desc.sample_count = impeller::SampleCount::kCount1; + } auto depth_stencil_tex = std::make_shared( gl_context.GetReactor(), depth_stencil_texture_desc, diff --git a/shell/platform/windows/compositor_opengl.cc b/shell/platform/windows/compositor_opengl.cc index dfefb09ba2e47..515959085c2be 100644 --- a/shell/platform/windows/compositor_opengl.cc +++ b/shell/platform/windows/compositor_opengl.cc @@ -23,8 +23,9 @@ struct FramebufferBackingStore { } // namespace CompositorOpenGL::CompositorOpenGL(FlutterWindowsEngine* engine, - impeller::ProcTableGLES::Resolver resolver) - : engine_(engine), resolver_(resolver) {} + impeller::ProcTableGLES::Resolver resolver, + bool enable_impeller) + : engine_(engine), resolver_(resolver), enable_impeller_(enable_impeller) {} bool CompositorOpenGL::CreateBackingStore( const FlutterBackingStoreConfig& config, @@ -50,8 +51,33 @@ bool CompositorOpenGL::CreateBackingStore( GL_UNSIGNED_BYTE, nullptr); gl_->BindTexture(GL_TEXTURE_2D, 0); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - store->texture_id, 0); + if (enable_impeller_) { + // Impeller requries that its onscreen surface is Multisampled and already + // has depth/stencil attached in order for anti-aliasing to work. + gl_->FramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + store->texture_id, 0, 4); + + // Set up depth/stencil attachment for impeller renderer. + GLuint depth_stencil; + gl_->GenRenderbuffers(1, &depth_stencil); + gl_->BindRenderbuffer(GL_RENDERBUFFER, depth_stencil); + gl_->RenderbufferStorageMultisampleEXT( + GL_RENDERBUFFER, // target + 4, // samples + GL_DEPTH24_STENCIL8, // internal format + config.size.width, // width + config.size.height // height + ); + gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_stencil); + gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, depth_stencil); + + } else { + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, store->texture_id, 0); + } result->type = kFlutterBackingStoreTypeOpenGL; result->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; @@ -131,7 +157,6 @@ bool CompositorOpenGL::Present(FlutterWindowsView* view, // Prevents regressions like: https://github.com/flutter/flutter/issues/140828 // See OpenGL specification version 4.6, section 18.3.1. gl_->Disable(GL_SCISSOR_TEST); - gl_->BindFramebuffer(GL_READ_FRAMEBUFFER, source_id); gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, kWindowFrameBufferId); diff --git a/shell/platform/windows/compositor_opengl.h b/shell/platform/windows/compositor_opengl.h index d5b813da9653d..18451c467604d 100644 --- a/shell/platform/windows/compositor_opengl.h +++ b/shell/platform/windows/compositor_opengl.h @@ -19,7 +19,8 @@ namespace flutter { class CompositorOpenGL : public Compositor { public: CompositorOpenGL(FlutterWindowsEngine* engine, - impeller::ProcTableGLES::Resolver resolver); + impeller::ProcTableGLES::Resolver resolver, + bool enable_impeller); /// |Compositor| bool CreateBackingStore(const FlutterBackingStoreConfig& config, @@ -59,6 +60,9 @@ class CompositorOpenGL : public Compositor { // the compositor is initialized. TextureFormat format_; + // Whether the Impeller rendering backend is enabled. + bool enable_impeller_ = false; + // Initialize the compositor. This must run on the raster thread. bool Initialize(); diff --git a/shell/platform/windows/compositor_opengl_unittests.cc b/shell/platform/windows/compositor_opengl_unittests.cc index a7bc210866ae9..37099e24163c5 100644 --- a/shell/platform/windows/compositor_opengl_unittests.cc +++ b/shell/platform/windows/compositor_opengl_unittests.cc @@ -125,7 +125,22 @@ class CompositorOpenGLTest : public WindowsTest { TEST_F(CompositorOpenGLTest, CreateBackingStore) { UseHeadlessEngine(); - auto compositor = CompositorOpenGL{engine(), kMockResolver}; + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false}; + + FlutterBackingStoreConfig config = {}; + FlutterBackingStore backing_store = {}; + + EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true)); + ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store)); + ASSERT_TRUE(compositor.CollectBackingStore(&backing_store)); +} + +TEST_F(CompositorOpenGLTest, CreateBackingStoreImpeller) { + UseHeadlessEngine(); + + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/true}; FlutterBackingStoreConfig config = {}; FlutterBackingStore backing_store = {}; @@ -138,7 +153,8 @@ TEST_F(CompositorOpenGLTest, CreateBackingStore) { TEST_F(CompositorOpenGLTest, InitializationFailure) { UseHeadlessEngine(); - auto compositor = CompositorOpenGL{engine(), kMockResolver}; + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false}; FlutterBackingStoreConfig config = {}; FlutterBackingStore backing_store = {}; @@ -150,7 +166,8 @@ TEST_F(CompositorOpenGLTest, InitializationFailure) { TEST_F(CompositorOpenGLTest, Present) { UseEngineWithView(); - auto compositor = CompositorOpenGL{engine(), kMockResolver}; + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false}; FlutterBackingStoreConfig config = {}; FlutterBackingStore backing_store = {}; @@ -174,7 +191,8 @@ TEST_F(CompositorOpenGLTest, Present) { TEST_F(CompositorOpenGLTest, PresentEmpty) { UseEngineWithView(); - auto compositor = CompositorOpenGL{engine(), kMockResolver}; + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false}; // The context will be bound twice: first to initialize the compositor, second // to clear the surface. @@ -188,7 +206,8 @@ TEST_F(CompositorOpenGLTest, PresentEmpty) { TEST_F(CompositorOpenGLTest, NoSurfaceIgnored) { UseEngineWithView(/*add_surface = */ false); - auto compositor = CompositorOpenGL{engine(), kMockResolver}; + auto compositor = + CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false}; FlutterBackingStoreConfig config = {}; FlutterBackingStore backing_store = {}; diff --git a/shell/platform/windows/egl/manager.cc b/shell/platform/windows/egl/manager.cc index 2b827f863f803..dee75a47df546 100644 --- a/shell/platform/windows/egl/manager.cc +++ b/shell/platform/windows/egl/manager.cc @@ -14,23 +14,23 @@ namespace egl { int Manager::instance_count_ = 0; -std::unique_ptr Manager::Create(bool enable_impeller) { +std::unique_ptr Manager::Create() { std::unique_ptr manager; - manager.reset(new Manager(enable_impeller)); + manager.reset(new Manager()); if (!manager->IsValid()) { return nullptr; } return std::move(manager); } -Manager::Manager(bool enable_impeller) { +Manager::Manager() { ++instance_count_; if (!InitializeDisplay()) { return; } - if (!InitializeConfig(enable_impeller)) { + if (!InitializeConfig()) { return; } @@ -140,46 +140,19 @@ bool Manager::InitializeDisplay() { FML_UNREACHABLE(); } -bool Manager::InitializeConfig(bool enable_impeller) { +bool Manager::InitializeConfig() { const EGLint config_attributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, EGL_NONE}; - const EGLint impeller_config_attributes[] = { - EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 8, - EGL_SAMPLE_BUFFERS, 1, EGL_SAMPLES, 4, EGL_NONE}; - const EGLint impeller_config_attributes_no_msaa[] = { - EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 8, - EGL_NONE}; - - EGLBoolean result; EGLint num_config = 0; - if (enable_impeller) { - // First try the MSAA configuration. - result = ::eglChooseConfig(display_, impeller_config_attributes, &config_, - 1, &num_config); - - if (result == EGL_TRUE && num_config > 0) { - return true; - } + EGLBoolean result = + ::eglChooseConfig(display_, config_attributes, &config_, 1, &num_config); - // Next fall back to disabled MSAA. - result = ::eglChooseConfig(display_, impeller_config_attributes_no_msaa, - &config_, 1, &num_config); - if (result == EGL_TRUE && num_config == 0) { - return true; - } - } else { - result = ::eglChooseConfig(display_, config_attributes, &config_, 1, - &num_config); - - if (result == EGL_TRUE && num_config > 0) { - return true; - } + if (result == EGL_TRUE && num_config > 0) { + return true; } LogEGLError("Failed to choose EGL config"); diff --git a/shell/platform/windows/egl/manager.h b/shell/platform/windows/egl/manager.h index 4ef289549d9ef..b2fb50677391c 100644 --- a/shell/platform/windows/egl/manager.h +++ b/shell/platform/windows/egl/manager.h @@ -30,7 +30,7 @@ namespace egl { // destroy surfaces class Manager { public: - static std::unique_ptr Create(bool enable_impeller); + static std::unique_ptr Create(); virtual ~Manager(); @@ -74,7 +74,7 @@ class Manager { protected: // Creates a new surface manager retaining reference to the passed-in target // for the lifetime of the manager. - explicit Manager(bool enable_impeller); + explicit Manager(); private: // Number of active instances of Manager @@ -84,7 +84,7 @@ class Manager { bool InitializeDisplay(); // Initialize the EGL configs. - bool InitializeConfig(bool enable_impeller); + bool InitializeConfig(); // Initialize the EGL render and resource contexts. bool InitializeContexts(); diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 11885cb6cda91..d08591a10b520 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -194,7 +194,7 @@ FlutterWindowsEngine::FlutterWindowsEngine( enable_impeller_ = std::find(switches.begin(), switches.end(), "--enable-impeller=true") != switches.end(); - egl_manager_ = egl::Manager::Create(enable_impeller_); + egl_manager_ = egl::Manager::Create(); window_proc_delegate_manager_ = std::make_unique(); window_proc_delegate_manager_->RegisterTopLevelWindowProcDelegate( [](HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar, void* user_data, @@ -393,7 +393,8 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { // TODO(schectman) Pass the platform view manager to the compositor // constructors: https://github.com/flutter/flutter/issues/143375 - compositor_ = std::make_unique(this, resolver); + compositor_ = + std::make_unique(this, resolver, enable_impeller_); } else { compositor_ = std::make_unique(); } diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 6d0befe60c628..72ffc7a6bf694 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -31,7 +31,7 @@ namespace { // An EGL manager that initializes EGL but fails to create surfaces. class HalfBrokenEGLManager : public egl::Manager { public: - HalfBrokenEGLManager() : egl::Manager(/*enable_impeller = */ false) {} + HalfBrokenEGLManager() : egl::Manager() {} std::unique_ptr CreateWindowSurface(HWND hwnd, size_t width, size_t height) override { diff --git a/shell/platform/windows/testing/egl/mock_manager.h b/shell/platform/windows/testing/egl/mock_manager.h index 1bde275416e16..aa3fb48c87ac1 100644 --- a/shell/platform/windows/testing/egl/mock_manager.h +++ b/shell/platform/windows/testing/egl/mock_manager.h @@ -16,7 +16,7 @@ namespace egl { /// Mock for the |Manager| base class. class MockManager : public flutter::egl::Manager { public: - MockManager() : Manager(false) {} + MockManager() : Manager() {} MOCK_METHOD(std::unique_ptr, CreateWindowSurface,