diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index df052d43034..47e25aa5421 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -447,6 +447,8 @@ FILE: ../../../flutter/impeller/base/thread_safety.cc FILE: ../../../flutter/impeller/base/thread_safety.h FILE: ../../../flutter/impeller/base/validation.cc FILE: ../../../flutter/impeller/base/validation.h +FILE: ../../../flutter/impeller/base/version.cc +FILE: ../../../flutter/impeller/base/version.h FILE: ../../../flutter/impeller/blobcat/blob.cc FILE: ../../../flutter/impeller/blobcat/blob.h FILE: ../../../flutter/impeller/blobcat/blob_library.cc @@ -634,15 +636,15 @@ FILE: ../../../flutter/impeller/renderer/backend/gles/command_buffer_gles.cc FILE: ../../../flutter/impeller/renderer/backend/gles/command_buffer_gles.h FILE: ../../../flutter/impeller/renderer/backend/gles/context_gles.cc FILE: ../../../flutter/impeller/renderer/backend/gles/context_gles.h +FILE: ../../../flutter/impeller/renderer/backend/gles/description_gles.cc +FILE: ../../../flutter/impeller/renderer/backend/gles/description_gles.h FILE: ../../../flutter/impeller/renderer/backend/gles/device_buffer_gles.cc FILE: ../../../flutter/impeller/renderer/backend/gles/device_buffer_gles.h FILE: ../../../flutter/impeller/renderer/backend/gles/formats_gles.cc FILE: ../../../flutter/impeller/renderer/backend/gles/formats_gles.h -FILE: ../../../flutter/impeller/renderer/backend/gles/gl_description.cc -FILE: ../../../flutter/impeller/renderer/backend/gles/gl_description.h FILE: ../../../flutter/impeller/renderer/backend/gles/gles.h -FILE: ../../../flutter/impeller/renderer/backend/gles/gles_handle.cc -FILE: ../../../flutter/impeller/renderer/backend/gles/gles_handle.h +FILE: ../../../flutter/impeller/renderer/backend/gles/handle_gles.cc +FILE: ../../../flutter/impeller/renderer/backend/gles/handle_gles.h FILE: ../../../flutter/impeller/renderer/backend/gles/pipeline_gles.cc FILE: ../../../flutter/impeller/renderer/backend/gles/pipeline_gles.h FILE: ../../../flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -764,6 +766,16 @@ FILE: ../../../flutter/impeller/tessellator/dart/lib/tessellator.dart FILE: ../../../flutter/impeller/tessellator/tessellator.cc FILE: ../../../flutter/impeller/tessellator/tessellator.h FILE: ../../../flutter/impeller/tessellator/tessellator_unittests.cc +FILE: ../../../flutter/impeller/toolkit/egl/config.cc +FILE: ../../../flutter/impeller/toolkit/egl/config.h +FILE: ../../../flutter/impeller/toolkit/egl/context.cc +FILE: ../../../flutter/impeller/toolkit/egl/context.h +FILE: ../../../flutter/impeller/toolkit/egl/display.cc +FILE: ../../../flutter/impeller/toolkit/egl/display.h +FILE: ../../../flutter/impeller/toolkit/egl/egl.cc +FILE: ../../../flutter/impeller/toolkit/egl/egl.h +FILE: ../../../flutter/impeller/toolkit/egl/surface.cc +FILE: ../../../flutter/impeller/toolkit/egl/surface.h FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -1264,10 +1276,12 @@ FILE: ../../../flutter/shell/common/vsync_waiter_fallback.cc FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h FILE: ../../../flutter/shell/common/vsync_waiters_test.cc FILE: ../../../flutter/shell/common/vsync_waiters_test.h -FILE: ../../../flutter/shell/gpu/gpu_surface_gl.cc -FILE: ../../../flutter/shell/gpu/gpu_surface_gl.h FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.h +FILE: ../../../flutter/shell/gpu/gpu_surface_gl_impeller.cc +FILE: ../../../flutter/shell/gpu/gpu_surface_gl_impeller.h +FILE: ../../../flutter/shell/gpu/gpu_surface_gl_skia.cc +FILE: ../../../flutter/shell/gpu/gpu_surface_gl_skia.h FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.cc FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.h FILE: ../../../flutter/shell/gpu/gpu_surface_metal_impeller.h @@ -1285,11 +1299,15 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.h FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml FILE: ../../../flutter/shell/platform/android/android_choreographer.cc FILE: ../../../flutter/shell/platform/android/android_choreographer.h -FILE: ../../../flutter/shell/platform/android/android_context_gl.cc -FILE: ../../../flutter/shell/platform/android/android_context_gl.h +FILE: ../../../flutter/shell/platform/android/android_context_gl_impeller.cc +FILE: ../../../flutter/shell/platform/android/android_context_gl_impeller.h +FILE: ../../../flutter/shell/platform/android/android_context_gl_skia.cc +FILE: ../../../flutter/shell/platform/android/android_context_gl_skia.h FILE: ../../../flutter/shell/platform/android/android_context_gl_unittests.cc FILE: ../../../flutter/shell/platform/android/android_display.cc FILE: ../../../flutter/shell/platform/android/android_display.h +FILE: ../../../flutter/shell/platform/android/android_egl_surface.cc +FILE: ../../../flutter/shell/platform/android/android_egl_surface.h FILE: ../../../flutter/shell/platform/android/android_environment_gl.cc FILE: ../../../flutter/shell/platform/android/android_environment_gl.h FILE: ../../../flutter/shell/platform/android/android_exports.lst @@ -1300,8 +1318,10 @@ FILE: ../../../flutter/shell/platform/android/android_image_generator.h FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc FILE: ../../../flutter/shell/platform/android/android_shell_holder.h FILE: ../../../flutter/shell/platform/android/android_shell_holder_unittests.cc -FILE: ../../../flutter/shell/platform/android/android_surface_gl.cc -FILE: ../../../flutter/shell/platform/android/android_surface_gl.h +FILE: ../../../flutter/shell/platform/android/android_surface_gl_impeller.cc +FILE: ../../../flutter/shell/platform/android/android_surface_gl_impeller.h +FILE: ../../../flutter/shell/platform/android/android_surface_gl_skia.cc +FILE: ../../../flutter/shell/platform/android/android_surface_gl_skia.h FILE: ../../../flutter/shell/platform/android/android_surface_software.cc FILE: ../../../flutter/shell/platform/android/android_surface_software.h FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc diff --git a/engine/src/flutter/impeller/base/BUILD.gn b/engine/src/flutter/impeller/base/BUILD.gn index 5bb267d2a01..577d34d78f2 100644 --- a/engine/src/flutter/impeller/base/BUILD.gn +++ b/engine/src/flutter/impeller/base/BUILD.gn @@ -22,6 +22,8 @@ impeller_component("base") { "thread_safety.h", "validation.cc", "validation.h", + "version.cc", + "version.h", ] deps = [ "//flutter/fml" ] diff --git a/engine/src/flutter/impeller/base/strings.cc b/engine/src/flutter/impeller/base/strings.cc index 1b0762f4518..f73c2acf08c 100644 --- a/engine/src/flutter/impeller/base/strings.cc +++ b/engine/src/flutter/impeller/base/strings.cc @@ -18,4 +18,16 @@ std::string SPrintF(const char* format, ...) { return buffer; } +bool HasPrefix(const std::string& string, const std::string& prefix) { + return string.find(prefix) == 0u; +} + +std::string StripPrefix(const std::string& string, + const std::string& to_strip) { + if (!HasPrefix(string, to_strip)) { + return string; + } + return string.substr(to_strip.length()); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/base/strings.h b/engine/src/flutter/impeller/base/strings.h index 179ae3f6da7..1a2c0d30669 100644 --- a/engine/src/flutter/impeller/base/strings.h +++ b/engine/src/flutter/impeller/base/strings.h @@ -13,4 +13,8 @@ namespace impeller { IMPELLER_PRINTF_FORMAT(1, 2) std::string SPrintF(const char* format, ...); +bool HasPrefix(const std::string& string, const std::string& prefix); + +std::string StripPrefix(const std::string& string, const std::string& to_strip); + } // namespace impeller diff --git a/engine/src/flutter/impeller/base/version.cc b/engine/src/flutter/impeller/base/version.cc new file mode 100644 index 00000000000..910e106aa1a --- /dev/null +++ b/engine/src/flutter/impeller/base/version.cc @@ -0,0 +1,33 @@ +// 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 "impeller/base/version.h" + +#include + +namespace impeller { + +std::optional Version::FromVector(const std::vector& version) { + if (version.size() == 0) { + return Version{0, 0, 0}; + } + if (version.size() == 1) { + return Version{version[0], 0, 0}; + } + if (version.size() == 2) { + return Version{version[0], version[1], 0}; + } + if (version.size() == 3) { + return Version{version[0], version[1], version[2]}; + } + return std::nullopt; +} + +std::string Version::ToString() const { + std::stringstream stream; + stream << major << "." << minor << "." << patch; + return stream.str(); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/base/version.h b/engine/src/flutter/impeller/base/version.h new file mode 100644 index 00000000000..b042ce268ae --- /dev/null +++ b/engine/src/flutter/impeller/base/version.h @@ -0,0 +1,34 @@ +// 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. + +#pragma once + +#include +#include +#include +#include +#include + +namespace impeller { + +struct Version { + public: + size_t major; + size_t minor; + size_t patch; + + constexpr Version(size_t p_major = 0, size_t p_minor = 0, size_t p_patch = 0) + : major(p_major), minor(p_minor), patch(p_patch) {} + + static std::optional FromVector(const std::vector& version); + + constexpr bool IsAtLeast(const Version& other) { + return std::tie(major, minor, patch) >= + std::tie(other.major, other.minor, other.patch); + } + + std::string ToString() const; +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn index 45b12597390..14e6f5fcc97 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn @@ -5,9 +5,12 @@ import("../../../tools/impeller.gni") config("gles_config") { - # Generic GL/GLES/EGL/Vulkan headers. Any will do. We just pick one from Angle - # because they are there. - include_dirs = [ "//third_party/angle/include" ] + include_dirs = [] + if (!is_android) { + # Generic GL/GLES/EGL/Vulkan headers. Any will do. We just pick one from Angle + # because they are there. + include_dirs = [ "//third_party/angle/include" ] + } } impeller_component("gles") { @@ -22,15 +25,15 @@ impeller_component("gles") { "command_buffer_gles.h", "context_gles.cc", "context_gles.h", + "description_gles.cc", + "description_gles.h", "device_buffer_gles.cc", "device_buffer_gles.h", "formats_gles.cc", "formats_gles.h", - "gl_description.cc", - "gl_description.h", "gles.h", - "gles_handle.cc", - "gles_handle.h", + "handle_gles.cc", + "handle_gles.h", "pipeline_gles.cc", "pipeline_gles.h", "pipeline_library_gles.cc", diff --git a/engine/src/flutter/impeller/renderer/backend/gles/description_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/description_gles.cc new file mode 100644 index 00000000000..762ad15f6dc --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/gles/description_gles.cc @@ -0,0 +1,148 @@ +// 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 "impeller/renderer/backend/gles/description_gles.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "impeller/base/strings.h" +#include "impeller/base/validation.h" +#include "impeller/renderer/backend/gles/proc_table_gles.h" + +namespace impeller { + +static std::string GetGLString(const ProcTableGLES& gl, GLenum name) { + auto str = gl.GetString(name); + if (str == nullptr) { + return ""; + } + return reinterpret_cast(str); +} + +static bool DetermineIfES(const std::string& version) { + return HasPrefix(version, "OpenGL ES"); +} + +static std::optional DetermineVersion(std::string version) { + // Format for OpenGL "OpenGLES". + // + // Format for OpenGL SL "OpenGLESGLSLES" + // + // The prefixes appear to be absent on Desktop GL. + + version = StripPrefix(version, "OpenGL ES "); + version = StripPrefix(version, "GLSL ES "); + + if (version.empty()) { + return std::nullopt; + } + + std::stringstream stream; + for (size_t i = 0; i < version.size(); i++) { + const auto character = version[i]; + if (std::isdigit(character) || character == '.') { + stream << character; + } else { + break; + } + } + std::istringstream istream; + istream.str(stream.str()); + std::vector version_components; + for (std::string version_component; + std::getline(istream, version_component, '.');) { + version_components.push_back(std::stoul(version_component)); + } + return Version::FromVector(std::move(version_components)); +} + +DescriptionGLES::DescriptionGLES(const ProcTableGLES& gl) + : vendor_(GetGLString(gl, GL_VENDOR)), + renderer_(GetGLString(gl, GL_RENDERER)), + gl_version_string_(GetGLString(gl, GL_VERSION)), + sl_version_string_(GetGLString(gl, GL_SHADING_LANGUAGE_VERSION)) { + const auto extensions = GetGLString(gl, GL_EXTENSIONS); + std::stringstream extensions_stream(extensions); + std::string extension; + while (std::getline(extensions_stream, extension, ' ')) { + extensions_.insert(extension); + } + + is_es_ = DetermineIfES(gl_version_string_); + + auto gl_version = DetermineVersion(gl_version_string_); + if (!gl_version.has_value()) { + VALIDATION_LOG << "Could not determine GL version."; + return; + } + gl_version_ = gl_version.value(); + + auto sl_version = DetermineVersion(sl_version_string_); + if (!sl_version.has_value()) { + VALIDATION_LOG << "Could not determine SL version."; + return; + } + sl_version_ = sl_version.value(); + + is_valid_ = true; +} + +DescriptionGLES::~DescriptionGLES() = default; + +bool DescriptionGLES::IsValid() const { + return is_valid_; +} + +std::string DescriptionGLES::GetString() const { + if (!IsValid()) { + return "Unknown Renderer."; + } + + std::vector> items; + + items.emplace_back(std::make_pair("Vendor", vendor_)); + items.emplace_back(std::make_pair("Renderer", renderer_)); + items.emplace_back(std::make_pair("GL Version", gl_version_string_)); + items.emplace_back( + std::make_pair("Shading Language Version", sl_version_string_)); + items.emplace_back( + std::make_pair("Extensions", std::to_string(extensions_.size()))); + + size_t max_width = 0u; + for (const auto& item : items) { + max_width = std::max(max_width, item.first.size()); + } + + std::stringstream stream; + stream << "OpenGL Renderer:" << std::endl; + for (const auto& item : items) { + stream << std::setw(max_width + 1) << item.first << ": " << item.second + << std::endl; + } + + const auto pad = std::string(max_width + 3, ' '); + for (const auto& extension : extensions_) { + stream << pad << extension << std::endl; + } + + return stream.str(); +} + +bool DescriptionGLES::HasExtension(const std::string& ext) const { + return extensions_.find(ext) != extensions_.end(); +} + +bool DescriptionGLES::HasDebugExtension() const { + return HasExtension("GL_KHR_debug"); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/gl_description.h b/engine/src/flutter/impeller/renderer/backend/gles/description_gles.h similarity index 65% rename from engine/src/flutter/impeller/renderer/backend/gles/gl_description.h rename to engine/src/flutter/impeller/renderer/backend/gles/description_gles.h index 8cb5e6a76ca..087d74b6adf 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/gl_description.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/description_gles.h @@ -8,16 +8,17 @@ #include #include "flutter/fml/macros.h" +#include "impeller/base/version.h" namespace impeller { class ProcTableGLES; -class GLDescription { +class DescriptionGLES { public: - GLDescription(const ProcTableGLES& gl); + DescriptionGLES(const ProcTableGLES& gl); - ~GLDescription(); + ~DescriptionGLES(); bool IsValid() const; @@ -28,14 +29,17 @@ class GLDescription { bool HasDebugExtension() const; private: + Version gl_version_; + Version sl_version_; + bool is_es_ = true; std::string vendor_; std::string renderer_; - std::string gl_version_; - std::string sl_version_; + std::string gl_version_string_; + std::string sl_version_string_; std::set extensions_; bool is_valid_ = false; - FML_DISALLOW_COPY_AND_ASSIGN(GLDescription); + FML_DISALLOW_COPY_AND_ASSIGN(DescriptionGLES); }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc index e1b91fb5af3..6ee452972cc 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -17,7 +17,7 @@ DeviceBufferGLES::DeviceBufferGLES(ReactorGLES::Ref reactor, : DeviceBuffer(size, mode), reactor_(std::move(reactor)), handle_(reactor_ ? reactor_->CreateHandle(HandleType::kBuffer) - : GLESHandle::DeadHandle()) {} + : HandleGLES::DeadHandle()) {} // |DeviceBuffer| DeviceBufferGLES::~DeviceBufferGLES() { @@ -83,6 +83,7 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { gl.BufferData(target_type, data_->GetSize(), data_->GetMapping(), GL_STATIC_DRAW); uploaded_ = true; + reactor_->SetDebugLabel(handle_, label_); } return true; @@ -90,8 +91,9 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { // |DeviceBuffer| bool DeviceBufferGLES::SetLabel(const std::string& label) { - if (!handle_.IsDead()) { - reactor_->SetDebugLabel(handle_, std::move(label)); + label_ = label; + if (uploaded_) { + reactor_->SetDebugLabel(handle_, label_); } return true; } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h index 07639413962..bd2a48f98b3 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h @@ -31,7 +31,8 @@ class DeviceBufferGLES final private: ReactorGLES::Ref reactor_; - GLESHandle handle_; + HandleGLES handle_; + std::string label_; mutable std::shared_ptr data_; mutable bool uploaded_ = false; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/gl_description.cc b/engine/src/flutter/impeller/renderer/backend/gles/gl_description.cc deleted file mode 100644 index d9045a5295c..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/gles/gl_description.cc +++ /dev/null @@ -1,88 +0,0 @@ -// 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 "impeller/renderer/backend/gles/gl_description.h" - -#include -#include -#include -#include -#include -#include - -#include "impeller/renderer/backend/gles/proc_table_gles.h" - -namespace impeller { - -static std::string GetGLString(const ProcTableGLES& gl, GLenum name) { - auto str = gl.GetString(name); - if (str == nullptr) { - return ""; - } - return reinterpret_cast(str); -} - -GLDescription::GLDescription(const ProcTableGLES& gl) - : vendor_(GetGLString(gl, GL_VENDOR)), - renderer_(GetGLString(gl, GL_RENDERER)), - gl_version_(GetGLString(gl, GL_VERSION)), - sl_version_(GetGLString(gl, GL_SHADING_LANGUAGE_VERSION)) { - const auto extensions = GetGLString(gl, GL_EXTENSIONS); - std::stringstream extensions_stream(extensions); - std::string extension; - while (std::getline(extensions_stream, extension, ' ')) { - extensions_.insert(extension); - } - is_valid_ = true; -} - -GLDescription::~GLDescription() = default; - -bool GLDescription::IsValid() const { - return is_valid_; -} - -std::string GLDescription::GetString() const { - if (!IsValid()) { - return "Unknown Renderer."; - } - - std::vector> items; - - items.emplace_back(std::make_pair("Vendor", vendor_)); - items.emplace_back(std::make_pair("Renderer", renderer_)); - items.emplace_back(std::make_pair("GL Version", gl_version_)); - items.emplace_back(std::make_pair("Shading Language Version", sl_version_)); - items.emplace_back( - std::make_pair("Extensions", std::to_string(extensions_.size()))); - - size_t max_width = 0u; - for (const auto& item : items) { - max_width = std::max(max_width, item.first.size()); - } - - std::stringstream stream; - stream << "OpenGL Renderer:" << std::endl; - for (const auto& item : items) { - stream << std::setw(max_width + 1) << item.first << ": " << item.second - << std::endl; - } - - const auto pad = std::string(max_width + 3, ' '); - for (const auto& extension : extensions_) { - stream << pad << extension << std::endl; - } - - return stream.str(); -} - -bool GLDescription::HasExtension(const std::string& ext) const { - return extensions_.find(ext) != extensions_.end(); -} - -bool GLDescription::HasDebugExtension() const { - return HasExtension("GL_KHR_debug"); -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/gles_handle.cc b/engine/src/flutter/impeller/renderer/backend/gles/handle_gles.cc similarity index 79% rename from engine/src/flutter/impeller/renderer/backend/gles/gles_handle.cc rename to engine/src/flutter/impeller/renderer/backend/gles/handle_gles.cc index 20841b64863..578c39fd352 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/gles_handle.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/handle_gles.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/renderer/backend/gles/gles_handle.h" +#include "impeller/renderer/backend/gles/handle_gles.h" namespace impeller { diff --git a/engine/src/flutter/impeller/renderer/backend/gles/gles_handle.h b/engine/src/flutter/impeller/renderer/backend/gles/handle_gles.h similarity index 67% rename from engine/src/flutter/impeller/renderer/backend/gles/gles_handle.h rename to engine/src/flutter/impeller/renderer/backend/gles/handle_gles.h index afd503b31fe..8302709517c 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/gles_handle.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/handle_gles.h @@ -27,17 +27,17 @@ enum class HandleType { class ReactorGLES; -struct GLESHandle { +struct HandleGLES { HandleType type = HandleType::kUnknown; - static GLESHandle DeadHandle() { - return GLESHandle{HandleType::kUnknown, std::nullopt}; + static HandleGLES DeadHandle() { + return HandleGLES{HandleType::kUnknown, std::nullopt}; } constexpr bool IsDead() const { return !name_.has_value(); } struct Hash { - std::size_t operator()(const GLESHandle& handle) const { + std::size_t operator()(const HandleGLES& handle) const { return fml::HashCombine( std::underlying_type_t(handle.type), handle.name_); @@ -45,7 +45,7 @@ struct GLESHandle { }; struct Equal { - bool operator()(const GLESHandle& lhs, const GLESHandle& rhs) const { + bool operator()(const HandleGLES& lhs, const HandleGLES& rhs) const { return lhs.type == rhs.type && lhs.name_ == rhs.name_; } }; @@ -55,21 +55,21 @@ struct GLESHandle { std::optional name_; - GLESHandle(HandleType p_type, UniqueID p_name) + HandleGLES(HandleType p_type, UniqueID p_name) : type(p_type), name_(p_name) {} - GLESHandle(HandleType p_type, std::optional p_name) + HandleGLES(HandleType p_type, std::optional p_name) : type(p_type), name_(p_name) {} - static GLESHandle Create(HandleType type) { - return GLESHandle{type, UniqueID{}}; + static HandleGLES Create(HandleType type) { + return HandleGLES{type, UniqueID{}}; } }; using GLESHandleSet = - std::unordered_set; + std::unordered_set; template using GLESHandleMap = - std::unordered_map; + std::unordered_map; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc index 6cd907a88bf..fd0bb5ba084 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc @@ -12,7 +12,7 @@ PipelineGLES::PipelineGLES(ReactorGLES::Ref reactor, : Pipeline(std::move(library), std::move(desc)), reactor_(std::move(reactor)), handle_(reactor_ ? reactor_->CreateHandle(HandleType::kProgram) - : GLESHandle::DeadHandle()), + : HandleGLES::DeadHandle()), is_valid_(!handle_.IsDead()) { if (is_valid_) { reactor_->SetDebugLabel(handle_, GetDescriptor().GetLabel()); @@ -31,7 +31,7 @@ bool PipelineGLES::IsValid() const { return is_valid_; } -const GLESHandle& PipelineGLES::GetProgramHandle() const { +const HandleGLES& PipelineGLES::GetProgramHandle() const { return handle_; } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h index 2b775b9bff3..f0e7e21d481 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h @@ -7,7 +7,7 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/gles/buffer_bindings_gles.h" -#include "impeller/renderer/backend/gles/gles_handle.h" +#include "impeller/renderer/backend/gles/handle_gles.h" #include "impeller/renderer/backend/gles/reactor_gles.h" #include "impeller/renderer/pipeline.h" @@ -21,7 +21,7 @@ class PipelineGLES final : public Pipeline, // |Pipeline| ~PipelineGLES() override; - const GLESHandle& GetProgramHandle() const; + const HandleGLES& GetProgramHandle() const; [[nodiscard]] bool BindProgram() const; @@ -36,7 +36,7 @@ class PipelineGLES final : public Pipeline, friend PipelineLibraryGLES; ReactorGLES::Ref reactor_; - GLESHandle handle_; + HandleGLES handle_; std::unique_ptr buffer_bindings_; bool is_valid_ = false; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc index 4e1e11c8b6e..603f50ffe80 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc @@ -90,7 +90,7 @@ ProcTableGLES::ProcTableGLES(Resolver resolver) { #undef IMPELLER_PROC - description_ = std::make_unique(*this); + description_ = std::make_unique(*this); if (!description_->IsValid()) { return; @@ -125,7 +125,7 @@ void ProcTableGLES::ShaderSourceMapping(GLuint shader, ShaderSource(shader, 1u, sources, lengths); } -const GLDescription* ProcTableGLES::GetDescription() const { +const DescriptionGLES* ProcTableGLES::GetDescription() const { return description_.get(); } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h index a5d84256a8e..08dd16e049b 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h @@ -10,7 +10,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" -#include "impeller/renderer/backend/gles/gl_description.h" +#include "impeller/renderer/backend/gles/description_gles.h" #include "impeller/renderer/backend/gles/gles.h" namespace impeller { @@ -183,7 +183,7 @@ class ProcTableGLES { void ShaderSourceMapping(GLuint shader, const fml::Mapping& mapping) const; - const GLDescription* GetDescription() const; + const DescriptionGLES* GetDescription() const; std::string DescribeCurrentFramebuffer() const; @@ -199,7 +199,7 @@ class ProcTableGLES { private: bool is_valid_ = false; - std::unique_ptr description_; + std::unique_ptr description_; GLint debug_label_max_length_ = 0; FML_DISALLOW_COPY_AND_ASSIGN(ProcTableGLES); diff --git a/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.cc index 36b5b11d358..d68a7238006 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.cc @@ -36,7 +36,7 @@ const ProcTableGLES& ReactorGLES::GetProcTable() const { return *proc_table_; } -std::optional ReactorGLES::GetGLHandle(const GLESHandle& handle) const { +std::optional ReactorGLES::GetGLHandle(const HandleGLES& handle) const { auto found = live_gl_handles_.find(handle); if (found != live_gl_handles_.end()) { return found->second; @@ -101,20 +101,20 @@ static bool CollectGLHandle(const ProcTableGLES& gl, return false; } -GLESHandle ReactorGLES::CreateHandle(HandleType type) { +HandleGLES ReactorGLES::CreateHandle(HandleType type) { if (type == HandleType::kUnknown) { - return GLESHandle::DeadHandle(); + return HandleGLES::DeadHandle(); } - auto new_handle = GLESHandle::Create(type); + auto new_handle = HandleGLES::Create(type); if (new_handle.IsDead()) { - return GLESHandle::DeadHandle(); + return HandleGLES::DeadHandle(); } live_gl_handles_[new_handle] = in_reaction_ ? CreateGLHandle(GetProcTable(), type) : std::nullopt; return new_handle; } -void ReactorGLES::CollectHandle(GLESHandle handle) { +void ReactorGLES::CollectHandle(HandleGLES handle) { auto live_handle = live_gl_handles_.find(handle); if (live_handle == live_gl_handles_.end()) { return; @@ -219,7 +219,7 @@ bool ReactorGLES::ReactOnce() { return true; } -void ReactorGLES::SetDebugLabel(const GLESHandle& handle, std::string label) { +void ReactorGLES::SetDebugLabel(const HandleGLES& handle, std::string label) { if (!can_set_debug_labels_) { return; } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.h index 391cfce428a..4306f697bea 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.h @@ -10,7 +10,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/macros.h" -#include "impeller/renderer/backend/gles/gles_handle.h" +#include "impeller/renderer/backend/gles/handle_gles.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" namespace impeller { @@ -29,13 +29,13 @@ class ReactorGLES { const ProcTableGLES& GetProcTable() const; - std::optional GetGLHandle(const GLESHandle& handle) const; + std::optional GetGLHandle(const HandleGLES& handle) const; - GLESHandle CreateHandle(HandleType type); + HandleGLES CreateHandle(HandleType type); - void CollectHandle(GLESHandle handle); + void CollectHandle(HandleGLES handle); - void SetDebugLabel(const GLESHandle& handle, std::string label); + void SetDebugLabel(const HandleGLES& handle, std::string label); using Operation = std::function; [[nodiscard]] bool AddOperation(Operation operation); diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h index 7d579579447..788cfd3c6e6 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h @@ -6,7 +6,7 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" -#include "impeller/renderer/backend/gles/gles_handle.h" +#include "impeller/renderer/backend/gles/handle_gles.h" #include "impeller/renderer/backend/gles/reactor_gles.h" #include "impeller/renderer/texture.h" @@ -52,7 +52,7 @@ class TextureGLES final : public Texture, ReactorGLES::Ref reactor_; const Type type_; - GLESHandle handle_; + HandleGLES handle_; mutable bool contents_initialized_ = false; const bool is_wrapped_; std::string label_; diff --git a/engine/src/flutter/impeller/toolkit/egl/BUILD.gn b/engine/src/flutter/impeller/toolkit/egl/BUILD.gn new file mode 100644 index 00000000000..6393adb1482 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/BUILD.gn @@ -0,0 +1,27 @@ +# 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. + +import("../../tools/impeller.gni") + +impeller_component("egl") { + sources = [ + "config.cc", + "config.h", + "context.cc", + "context.h", + "display.cc", + "display.h", + "egl.cc", + "egl.h", + "surface.cc", + "surface.h", + ] + + deps = [ "//flutter/fml" ] + + libs = [] + if (is_android) { + libs = [ "EGL" ] + } +} diff --git a/engine/src/flutter/impeller/toolkit/egl/config.cc b/engine/src/flutter/impeller/toolkit/egl/config.cc new file mode 100644 index 00000000000..c52ed485349 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/config.cc @@ -0,0 +1,30 @@ +// 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 "impeller/toolkit/egl/config.h" + +#include + +namespace impeller { +namespace egl { + +Config::Config(ConfigDescriptor descriptor, EGLConfig config) + : desc_(std::move(descriptor)), config_(config) {} + +Config::~Config() = default; + +const ConfigDescriptor& Config::GetDescriptor() const { + return desc_; +} + +const EGLConfig& Config::GetHandle() const { + return config_; +} + +bool Config::IsValid() const { + return config_ != nullptr; +} + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/config.h b/engine/src/flutter/impeller/toolkit/egl/config.h new file mode 100644 index 00000000000..11d0101927f --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/config.h @@ -0,0 +1,74 @@ +// 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. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/toolkit/egl/egl.h" + +namespace impeller { +namespace egl { + +enum class API { + kOpenGL, + kOpenGLES2, + kOpenGLES3, +}; + +enum class Samples { + kOne = 1, + kTwo = 2, + kFour = 4, +}; + +enum class ColorFormat { + kRGBA8888, + kRGB565, +}; + +enum class StencilBits { + kZero = 0, + kEight = 8, +}; + +enum class DepthBits { + kZero = 0, + kEight = 8, +}; + +enum class SurfaceType { + kWindow, + kPBuffer, +}; + +struct ConfigDescriptor { + API api = API::kOpenGLES2; + Samples samples = Samples::kOne; + ColorFormat color_format = ColorFormat::kRGB565; + StencilBits stencil_bits = StencilBits::kZero; + DepthBits depth_bits = DepthBits::kZero; + SurfaceType surface_type = SurfaceType::kPBuffer; +}; + +class Config { + public: + Config(ConfigDescriptor descriptor, EGLConfig config); + + ~Config(); + + bool IsValid() const; + + const ConfigDescriptor& GetDescriptor() const; + + const EGLConfig& GetHandle() const; + + private: + const ConfigDescriptor desc_; + EGLConfig config_ = nullptr; + + FML_DISALLOW_COPY_AND_ASSIGN(Config); +}; + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/context.cc b/engine/src/flutter/impeller/toolkit/egl/context.cc new file mode 100644 index 00000000000..ed9c2241390 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/context.cc @@ -0,0 +1,73 @@ +// 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 "impeller/toolkit/egl/context.h" + +#include "impeller/toolkit/egl/surface.h" + +namespace impeller { +namespace egl { + +Context::Context(EGLDisplay display, EGLContext context) + : display_(display), context_(context) {} + +Context::~Context() { + if (context_ != EGL_NO_CONTEXT) { + if (::eglDestroyContext(display_, context_) != EGL_TRUE) { + IMPELLER_LOG_EGL_ERROR; + } + } +} + +bool Context::IsValid() const { + return context_ != EGL_NO_CONTEXT; +} + +const EGLContext& Context::GetHandle() const { + return context_; +} + +static EGLBoolean EGLMakeCurrentIfNecessary(EGLDisplay display, + EGLSurface draw, + EGLSurface read, + EGLContext context) { + if (display != ::eglGetCurrentDisplay() || + draw != ::eglGetCurrentSurface(EGL_DRAW) || + read != ::eglGetCurrentSurface(EGL_READ) || + context != ::eglGetCurrentContext()) { + return ::eglMakeCurrent(display, draw, read, context); + } + // The specified context configuration is already current. + return EGL_TRUE; +} + +bool Context::MakeCurrent(const Surface& surface) const { + if (context_ == EGL_NO_CONTEXT) { + return false; + } + const auto result = EGLMakeCurrentIfNecessary(display_, // + surface.GetHandle(), // + surface.GetHandle(), // + context_ // + ) == EGL_TRUE; + if (!result) { + IMPELLER_LOG_EGL_ERROR; + } + return result; +} + +bool Context::ClearCurrent() const { + const auto result = EGLMakeCurrentIfNecessary(display_, // + EGL_NO_SURFACE, // + EGL_NO_SURFACE, // + EGL_NO_CONTEXT // + ) == EGL_TRUE; + if (!result) { + IMPELLER_LOG_EGL_ERROR; + } + return result; +} + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/context.h b/engine/src/flutter/impeller/toolkit/egl/context.h new file mode 100644 index 00000000000..e5666c32897 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/context.h @@ -0,0 +1,37 @@ +// 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. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/toolkit/egl/egl.h" + +namespace impeller { +namespace egl { + +class Surface; + +class Context { + public: + Context(EGLDisplay display, EGLContext context); + + ~Context(); + + bool IsValid() const; + + const EGLContext& GetHandle() const; + + bool MakeCurrent(const Surface& surface) const; + + bool ClearCurrent() const; + + private: + EGLDisplay display_ = EGL_NO_DISPLAY; + EGLContext context_ = EGL_NO_CONTEXT; + + FML_DISALLOW_COPY_AND_ASSIGN(Context); +}; + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/display.cc b/engine/src/flutter/impeller/toolkit/egl/display.cc new file mode 100644 index 00000000000..2afb265c9f6 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/display.cc @@ -0,0 +1,210 @@ +// 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 "impeller/toolkit/egl/display.h" + +#include + +#include "impeller/toolkit/egl/context.h" +#include "impeller/toolkit/egl/surface.h" + +namespace impeller { +namespace egl { + +Display::Display() { + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + if (::eglInitialize(display, nullptr, nullptr) != EGL_TRUE) { + IMPELLER_LOG_EGL_ERROR; + return; + } + display_ = display; +} + +Display::~Display() { + if (display_ != EGL_NO_DISPLAY) { + if (::eglTerminate(display_) != EGL_TRUE) { + IMPELLER_LOG_EGL_ERROR; + } + } +} + +bool Display::IsValid() const { + return display_ != EGL_NO_DISPLAY; +} + +std::unique_ptr Display::CreateContext(const Config& config, + const Context* share_context) { + const auto& desc = config.GetDescriptor(); + + std::vector attributes; + switch (desc.api) { + case API::kOpenGL: + break; + case API::kOpenGLES2: + attributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + attributes.push_back(2); + break; + case API::kOpenGLES3: + attributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + attributes.push_back(3); + break; + } + // Termination sentinel must be present. + attributes.push_back(EGL_NONE); + + auto context = ::eglCreateContext( + display_, // display + config.GetHandle(), // config + share_context != nullptr ? share_context->GetHandle() : nullptr, // share + attributes.data() // attributes + ); + + if (context == EGL_NO_CONTEXT) { + IMPELLER_LOG_EGL_ERROR; + return nullptr; + } + + return std::make_unique(display_, context); +} + +std::unique_ptr Display::ChooseConfig(ConfigDescriptor config) const { + if (!display_) { + return nullptr; + } + + std::vector attributes; + + { + attributes.push_back(EGL_RENDERABLE_TYPE); + switch (config.api) { + case API::kOpenGL: + attributes.push_back(EGL_OPENGL_BIT); + break; + case API::kOpenGLES2: + attributes.push_back(EGL_OPENGL_ES2_BIT); + break; + case API::kOpenGLES3: + attributes.push_back(EGL_OPENGL_ES3_BIT); + break; + } + } + + { + attributes.push_back(EGL_SURFACE_TYPE); + switch (config.surface_type) { + case SurfaceType::kWindow: + attributes.push_back(EGL_WINDOW_BIT); + break; + case SurfaceType::kPBuffer: + attributes.push_back(EGL_PBUFFER_BIT); + break; + } + } + + { + switch (config.color_format) { + case ColorFormat::kRGBA8888: + attributes.push_back(EGL_RED_SIZE); + attributes.push_back(8); + attributes.push_back(EGL_GREEN_SIZE); + attributes.push_back(8); + attributes.push_back(EGL_BLUE_SIZE); + attributes.push_back(8); + attributes.push_back(EGL_ALPHA_SIZE); + attributes.push_back(8); + break; + case ColorFormat::kRGB565: + attributes.push_back(EGL_RED_SIZE); + attributes.push_back(5); + attributes.push_back(EGL_GREEN_SIZE); + attributes.push_back(6); + attributes.push_back(EGL_BLUE_SIZE); + attributes.push_back(5); + break; + } + } + + { + attributes.push_back(EGL_DEPTH_SIZE); + attributes.push_back(static_cast(config.depth_bits)); + } + + { + attributes.push_back(EGL_STENCIL_SIZE); + attributes.push_back(static_cast(config.stencil_bits)); + } + + { + const auto sample_count = static_cast(config.samples); + if (sample_count > 1) { + attributes.push_back(EGL_SAMPLE_BUFFERS); + attributes.push_back(1); + } + attributes.push_back(EGL_SAMPLES); + attributes.push_back(sample_count); + } + + // termination sentinel must be present. + attributes.push_back(EGL_NONE); + + EGLConfig config_out = nullptr; + EGLint config_count_out = 0; + if (::eglChooseConfig(display_, // display + attributes.data(), // attributes (null terminated) + &config_out, // matched configs + 1, // configs array size + &config_count_out // match configs count + ) != EGL_TRUE) { + IMPELLER_LOG_EGL_ERROR; + return nullptr; + } + + if (config_count_out != 1u) { + IMPELLER_LOG_EGL_ERROR; + return nullptr; + } + + return std::make_unique(std::move(config), config_out); +} + +std::unique_ptr Display::CreateWindowSurface( + const Config& config, + EGLNativeWindowType window) { + const EGLint attribs[] = {EGL_NONE}; + auto surface = ::eglCreateWindowSurface(display_, // display + config.GetHandle(), // config + window, // window + attribs // attrib_list + ); + if (surface == EGL_NO_SURFACE) { + IMPELLER_LOG_EGL_ERROR; + return nullptr; + } + return std::make_unique(display_, surface); +} + +std::unique_ptr Display::CreatePixelBufferSurface(const Config& config, + size_t width, + size_t height) { + // clang-format off + const EGLint attribs[] = { + EGL_WIDTH, static_cast(width), + EGL_HEIGHT, static_cast(height), + EGL_NONE + }; + // clang-format on + auto surface = ::eglCreatePbufferSurface(display_, // display + config.GetHandle(), // config + attribs // attrib_list + ); + if (surface == EGL_NO_SURFACE) { + IMPELLER_LOG_EGL_ERROR; + return nullptr; + } + return std::make_unique(display_, surface); +} + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/display.h b/engine/src/flutter/impeller/toolkit/egl/display.h new file mode 100644 index 00000000000..07f5d251291 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/display.h @@ -0,0 +1,47 @@ +// 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. + +#pragma once + +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/toolkit/egl/config.h" +#include "impeller/toolkit/egl/egl.h" + +namespace impeller { +namespace egl { + +class Context; +class Surface; + +class Display { + public: + Display(); + + ~Display(); + + bool IsValid() const; + + std::unique_ptr ChooseConfig(ConfigDescriptor config) const; + + std::unique_ptr CreateContext(const Config& config, + const Context* share_context); + + std::unique_ptr CreateWindowSurface(const Config& config, + EGLNativeWindowType window); + + std::unique_ptr CreatePixelBufferSurface(const Config& config, + size_t width, + size_t height); + + private: + EGLDisplay display_ = EGL_NO_DISPLAY; + + FML_DISALLOW_COPY_AND_ASSIGN(Display); +}; + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/egl.cc b/engine/src/flutter/impeller/toolkit/egl/egl.cc new file mode 100644 index 00000000000..54abfecee24 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/egl.cc @@ -0,0 +1,61 @@ +// 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 "impeller/toolkit/egl/egl.h" + +#include "flutter/fml/logging.h" + +namespace impeller { +namespace egl { + +std::function CreateProcAddressResolver() { + return [](const char* name) -> void* { + return reinterpret_cast(::eglGetProcAddress(name)); + }; +} + +static const char* EGLErrorToString(EGLint error) { + switch (error) { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "Not Initialized"; + case EGL_BAD_ACCESS: + return "Bad Access"; + case EGL_BAD_ALLOC: + return "Bad Alloc"; + case EGL_BAD_ATTRIBUTE: + return "Bad Attribute"; + case EGL_BAD_CONTEXT: + return "Bad Context"; + case EGL_BAD_CONFIG: + return "Bad Config"; + case EGL_BAD_CURRENT_SURFACE: + return "Bad Current Surface"; + case EGL_BAD_DISPLAY: + return "Bad Display"; + case EGL_BAD_SURFACE: + return "Bad Surface"; + case EGL_BAD_MATCH: + return "Bad Match"; + case EGL_BAD_PARAMETER: + return "Bad Parameter"; + case EGL_BAD_NATIVE_PIXMAP: + return "Bad Native Pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "Bad Native Window"; + case EGL_CONTEXT_LOST: + return "Context Lost"; + } + return "Unknown"; +} + +void LogEGLError(const char* file, int line) { + const auto error = ::eglGetError(); + FML_LOG(ERROR) << "EGL Error: " << EGLErrorToString(error) << " (" << error + << ") in " << file << ":" << line; +} + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/egl.h b/engine/src/flutter/impeller/toolkit/egl/egl.h new file mode 100644 index 00000000000..63c57075d63 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/egl.h @@ -0,0 +1,21 @@ +// 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. + +#pragma once + +#include + +#include + +namespace impeller { +namespace egl { + +std::function CreateProcAddressResolver(); + +#define IMPELLER_LOG_EGL_ERROR LogEGLError(__FILE__, __LINE__); + +void LogEGLError(const char* file, int line); + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/surface.cc b/engine/src/flutter/impeller/toolkit/egl/surface.cc new file mode 100644 index 00000000000..54fc614cd11 --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/surface.cc @@ -0,0 +1,38 @@ +// 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 "impeller/toolkit/egl/surface.h" + +namespace impeller { +namespace egl { + +Surface::Surface(EGLDisplay display, EGLSurface surface) + : display_(display), surface_(surface) {} + +Surface::~Surface() { + if (surface_ != EGL_NO_SURFACE) { + if (::eglDestroySurface(display_, surface_) != EGL_TRUE) { + IMPELLER_LOG_EGL_ERROR; + } + } +} + +const EGLSurface& Surface::GetHandle() const { + return surface_; +} + +bool Surface::IsValid() const { + return surface_ != EGL_NO_SURFACE; +} + +bool Surface::Present() const { + const auto result = ::eglSwapBuffers(display_, surface_) == EGL_TRUE; + if (!result) { + IMPELLER_LOG_EGL_ERROR; + } + return result; +} + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/egl/surface.h b/engine/src/flutter/impeller/toolkit/egl/surface.h new file mode 100644 index 00000000000..e506bf1fe8c --- /dev/null +++ b/engine/src/flutter/impeller/toolkit/egl/surface.h @@ -0,0 +1,33 @@ +// 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. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/toolkit/egl/egl.h" + +namespace impeller { +namespace egl { + +class Surface { + public: + Surface(EGLDisplay display, EGLSurface surface); + + ~Surface(); + + bool IsValid() const; + + const EGLSurface& GetHandle() const; + + bool Present() const; + + private: + EGLDisplay display_ = EGL_NO_DISPLAY; + EGLSurface surface_ = EGL_NO_SURFACE; + + FML_DISALLOW_COPY_AND_ASSIGN(Surface); +}; + +} // namespace egl +} // namespace impeller diff --git a/engine/src/flutter/impeller/tools/impeller.gni b/engine/src/flutter/impeller/tools/impeller.gni index 52b3d778e49..162e7895c24 100644 --- a/engine/src/flutter/impeller/tools/impeller.gni +++ b/engine/src/flutter/impeller/tools/impeller.gni @@ -17,7 +17,7 @@ declare_args() { impeller_enable_metal = is_mac || is_ios # Whether the OpenGLES backend is enabled. - impeller_enable_opengles = is_mac || is_linux + impeller_enable_opengles = is_mac || is_linux || is_android # Whether to use a prebuilt impellerc. # If this is the empty string, impellerc will be built. diff --git a/engine/src/flutter/shell/common/shell_test_platform_view_gl.cc b/engine/src/flutter/shell/common/shell_test_platform_view_gl.cc index 0c7d5d6f727..4bd7423ed22 100644 --- a/engine/src/flutter/shell/common/shell_test_platform_view_gl.cc +++ b/engine/src/flutter/shell/common/shell_test_platform_view_gl.cc @@ -4,7 +4,7 @@ #include "flutter/shell/common/shell_test_platform_view_gl.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" namespace flutter { namespace testing { @@ -35,7 +35,7 @@ void ShellTestPlatformViewGL::SimulateVSync() { // |PlatformView| std::unique_ptr ShellTestPlatformViewGL::CreateRenderingSurface() { - return std::make_unique(this, true); + return std::make_unique(this, true); } // |PlatformView| diff --git a/engine/src/flutter/shell/gpu/BUILD.gn b/engine/src/flutter/shell/gpu/BUILD.gn index 019c472e25e..6c5a86812d1 100644 --- a/engine/src/flutter/shell/gpu/BUILD.gn +++ b/engine/src/flutter/shell/gpu/BUILD.gn @@ -3,6 +3,7 @@ # found in the LICENSE file. import("//flutter/common/config.gni") +import("//flutter/impeller/tools/impeller.gni") import("//flutter/shell/config.gni") gpu_common_deps = [ @@ -27,13 +28,22 @@ source_set("gpu_surface_software") { source_set("gpu_surface_gl") { sources = [ - "gpu_surface_gl.cc", - "gpu_surface_gl.h", "gpu_surface_gl_delegate.cc", "gpu_surface_gl_delegate.h", + "gpu_surface_gl_skia.cc", + "gpu_surface_gl_skia.h", ] public_deps = gpu_common_deps + + if (impeller_enable_opengles) { + sources += [ + "gpu_surface_gl_impeller.cc", + "gpu_surface_gl_impeller.h", + ] + + public_deps += [ "//flutter/impeller" ] + } } source_set("gpu_surface_vulkan") { diff --git a/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc new file mode 100644 index 00000000000..e09b9809cc9 --- /dev/null +++ b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.cc @@ -0,0 +1,153 @@ +// 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/gpu/gpu_surface_gl_impeller.h" + +#include "flutter/fml/make_copyable.h" +#include "flutter/impeller/display_list/display_list_dispatcher.h" +#include "flutter/impeller/renderer/backend/gles/surface_gles.h" +#include "flutter/impeller/renderer/renderer.h" + +namespace flutter { + +GPUSurfaceGLImpeller::GPUSurfaceGLImpeller( + GPUSurfaceGLDelegate* delegate, + std::shared_ptr context) + : weak_factory_(this) { + if (delegate == nullptr) { + return; + } + + if (!context || !context->IsValid()) { + return; + } + + auto renderer = std::make_shared(context); + if (!renderer->IsValid()) { + return; + } + + auto aiks_context = std::make_shared(context); + + if (!aiks_context->IsValid()) { + return; + } + + delegate_ = delegate; + impeller_context_ = std::move(context); + impeller_renderer_ = std::move(renderer); + aiks_context_ = std::move(aiks_context); + is_valid_ = true; +} + +// |Surface| +GPUSurfaceGLImpeller::~GPUSurfaceGLImpeller() = default; + +// |Surface| +bool GPUSurfaceGLImpeller::IsValid() { + return is_valid_; +} + +// |Surface| +std::unique_ptr GPUSurfaceGLImpeller::AcquireFrame( + const SkISize& size) { + if (!IsValid()) { + FML_LOG(ERROR) << "OpenGL surface was invalid."; + return nullptr; + } + + auto swap_callback = [weak = weak_factory_.GetWeakPtr(), + delegate = delegate_]() -> bool { + if (weak) { + delegate->GLContextPresent(0u, std::nullopt); + } + return true; + }; + + auto context_switch = delegate_->GLContextMakeCurrent(); + if (!context_switch->GetResult()) { + FML_LOG(ERROR) + << "Could not make the context current to acquire the frame."; + return nullptr; + } + + auto surface = impeller::SurfaceGLES::WrapFBO( + impeller_context_, // context + swap_callback, // swap_callback + 0u, // fbo + impeller::PixelFormat::kR8G8B8A8UNormInt, // color_format + impeller::ISize{size.width(), size.height()} // fbo_size + ); + + SurfaceFrame::SubmitCallback submit_callback = + fml::MakeCopyable([renderer = impeller_renderer_, // + aiks_context = aiks_context_, // + surface = std::move(surface) // + ](SurfaceFrame& surface_frame, SkCanvas* canvas) mutable -> bool { + if (!aiks_context) { + return false; + } + + auto display_list = surface_frame.BuildDisplayList(); + if (!display_list) { + FML_LOG(ERROR) << "Could not build display list for surface frame."; + return false; + } + + impeller::DisplayListDispatcher impeller_dispatcher; + display_list->Dispatch(impeller_dispatcher); + auto picture = impeller_dispatcher.EndRecordingAsPicture(); + + return renderer->Render( + std::move(surface), + fml::MakeCopyable( + [aiks_context, picture = std::move(picture)]( + impeller::RenderTarget& render_target) -> bool { + return aiks_context->Render(picture, render_target); + })); + }); + + return std::make_unique( + nullptr, // surface + SurfaceFrame::FramebufferInfo{}, // framebuffer info + submit_callback, // submit callback + std::move(context_switch), // context result + true // display list fallback + ); +} + +// |Surface| +SkMatrix GPUSurfaceGLImpeller::GetRootTransformation() const { + // This backend does not currently support root surface transformations. Just + // return identity. + return {}; +} + +// |Surface| +GrDirectContext* GPUSurfaceGLImpeller::GetContext() { + // Impeller != Skia. + return nullptr; +} + +// |Surface| +std::unique_ptr +GPUSurfaceGLImpeller::MakeRenderContextCurrent() { + return delegate_->GLContextMakeCurrent(); +} + +// |Surface| +bool GPUSurfaceGLImpeller::ClearRenderContext() { + return delegate_->GLContextClearCurrent(); +} + +bool GPUSurfaceGLImpeller::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + +// |Surface| +bool GPUSurfaceGLImpeller::EnableRasterCache() const { + return false; +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.h b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.h new file mode 100644 index 00000000000..2e2772813b1 --- /dev/null +++ b/engine/src/flutter/shell/gpu/gpu_surface_gl_impeller.h @@ -0,0 +1,63 @@ +// 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 SHELL_GPU_GPU_SURFACE_GL_IMPELLER_H_ +#define SHELL_GPU_GPU_SURFACE_GL_IMPELLER_H_ + +#include "flutter/common/graphics/gl_context_switch.h" +#include "flutter/flow/surface.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/impeller/aiks/aiks_context.h" +#include "flutter/impeller/renderer/context.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" + +namespace flutter { + +class GPUSurfaceGLImpeller final : public Surface { + public: + explicit GPUSurfaceGLImpeller(GPUSurfaceGLDelegate* delegate, + std::shared_ptr context); + + // |Surface| + ~GPUSurfaceGLImpeller() override; + + // |Surface| + bool IsValid() override; + + private: + GPUSurfaceGLDelegate* delegate_ = nullptr; + std::shared_ptr impeller_context_; + std::shared_ptr impeller_renderer_; + std::shared_ptr aiks_context_; + bool is_valid_ = false; + fml::WeakPtrFactory weak_factory_; + + // |Surface| + std::unique_ptr AcquireFrame(const SkISize& size) override; + + // |Surface| + SkMatrix GetRootTransformation() const override; + + // |Surface| + GrDirectContext* GetContext() override; + + // |Surface| + std::unique_ptr MakeRenderContextCurrent() override; + + // |Surface| + bool ClearRenderContext() override; + + // |Surface| + bool AllowsDrawingWhenGpuDisabled() const override; + + // |Surface| + bool EnableRasterCache() const override; + + FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGLImpeller); +}; + +} // namespace flutter + +#endif // SHELL_GPU_GPU_SURFACE_GL_IMPELLER_H_ diff --git a/engine/src/flutter/shell/gpu/gpu_surface_gl.cc b/engine/src/flutter/shell/gpu/gpu_surface_gl_skia.cc similarity index 89% rename from engine/src/flutter/shell/gpu/gpu_surface_gl.cc rename to engine/src/flutter/shell/gpu/gpu_surface_gl_skia.cc index 068ae70519a..ab26189ac69 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_gl.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_gl_skia.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #include "flutter/common/graphics/persistent_cache.h" #include "flutter/fml/base32.h" @@ -35,7 +35,7 @@ namespace flutter { // system channel. static const size_t kGrCacheMaxByteSize = 24 * (1 << 20); -sk_sp GPUSurfaceGL::MakeGLContext( +sk_sp GPUSurfaceGLSkia::MakeGLContext( GPUSurfaceGLDelegate* delegate) { auto context_switch = delegate->GLContextMakeCurrent(); if (!context_switch->GetResult()) { @@ -61,15 +61,15 @@ sk_sp GPUSurfaceGL::MakeGLContext( return context; } -GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, - bool render_to_surface) - : GPUSurfaceGL(MakeGLContext(delegate), delegate, render_to_surface) { +GPUSurfaceGLSkia::GPUSurfaceGLSkia(GPUSurfaceGLDelegate* delegate, + bool render_to_surface) + : GPUSurfaceGLSkia(MakeGLContext(delegate), delegate, render_to_surface) { context_owner_ = true; } -GPUSurfaceGL::GPUSurfaceGL(sk_sp gr_context, - GPUSurfaceGLDelegate* delegate, - bool render_to_surface) +GPUSurfaceGLSkia::GPUSurfaceGLSkia(sk_sp gr_context, + GPUSurfaceGLDelegate* delegate, + bool render_to_surface) : delegate_(delegate), context_(gr_context), context_owner_(false), @@ -87,7 +87,7 @@ GPUSurfaceGL::GPUSurfaceGL(sk_sp gr_context, valid_ = gr_context != nullptr; } -GPUSurfaceGL::~GPUSurfaceGL() { +GPUSurfaceGLSkia::~GPUSurfaceGLSkia() { if (!valid_) { return; } @@ -109,7 +109,7 @@ GPUSurfaceGL::~GPUSurfaceGL() { } // |Surface| -bool GPUSurfaceGL::IsValid() { +bool GPUSurfaceGLSkia::IsValid() { return valid_; } @@ -156,7 +156,7 @@ static sk_sp WrapOnscreenSurface(GrDirectContext* context, ); } -bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) { +bool GPUSurfaceGLSkia::CreateOrUpdateSurfaces(const SkISize& size) { if (onscreen_surface_ != nullptr && size == SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height())) { @@ -200,12 +200,13 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) { } // |Surface| -SkMatrix GPUSurfaceGL::GetRootTransformation() const { +SkMatrix GPUSurfaceGLSkia::GetRootTransformation() const { return delegate_->GLContextSurfaceTransformation(); } // |Surface| -std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { +std::unique_ptr GPUSurfaceGLSkia::AcquireFrame( + const SkISize& size) { if (delegate_ == nullptr) { return nullptr; } @@ -251,7 +252,8 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { std::move(context_switch)); } -bool GPUSurfaceGL::PresentSurface(const SurfaceFrame& frame, SkCanvas* canvas) { +bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame, + SkCanvas* canvas) { if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) { return false; } @@ -294,7 +296,7 @@ bool GPUSurfaceGL::PresentSurface(const SurfaceFrame& frame, SkCanvas* canvas) { return true; } -sk_sp GPUSurfaceGL::AcquireRenderSurface( +sk_sp GPUSurfaceGLSkia::AcquireRenderSurface( const SkISize& untransformed_size, const SkMatrix& root_surface_transformation) { const auto transformed_rect = root_surface_transformation.mapRect( @@ -311,22 +313,22 @@ sk_sp GPUSurfaceGL::AcquireRenderSurface( } // |Surface| -GrDirectContext* GPUSurfaceGL::GetContext() { +GrDirectContext* GPUSurfaceGLSkia::GetContext() { return context_.get(); } // |Surface| -std::unique_ptr GPUSurfaceGL::MakeRenderContextCurrent() { +std::unique_ptr GPUSurfaceGLSkia::MakeRenderContextCurrent() { return delegate_->GLContextMakeCurrent(); } // |Surface| -bool GPUSurfaceGL::ClearRenderContext() { +bool GPUSurfaceGLSkia::ClearRenderContext() { return delegate_->GLContextClearCurrent(); } // |Surface| -bool GPUSurfaceGL::AllowsDrawingWhenGpuDisabled() const { +bool GPUSurfaceGLSkia::AllowsDrawingWhenGpuDisabled() const { return delegate_->AllowsDrawingWhenGpuDisabled(); } diff --git a/engine/src/flutter/shell/gpu/gpu_surface_gl.h b/engine/src/flutter/shell/gpu/gpu_surface_gl_skia.h similarity index 79% rename from engine/src/flutter/shell/gpu/gpu_surface_gl.h rename to engine/src/flutter/shell/gpu/gpu_surface_gl_skia.h index 390d78bbb9c..90cad241945 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_gl.h +++ b/engine/src/flutter/shell/gpu/gpu_surface_gl_skia.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SHELL_GPU_GPU_SURFACE_GL_H_ -#define SHELL_GPU_GPU_SURFACE_GL_H_ +#ifndef SHELL_GPU_GPU_SURFACE_GL_SKIA_H_ +#define SHELL_GPU_GPU_SURFACE_GL_SKIA_H_ #include #include @@ -18,19 +18,19 @@ namespace flutter { -class GPUSurfaceGL : public Surface { +class GPUSurfaceGLSkia : public Surface { public: static sk_sp MakeGLContext(GPUSurfaceGLDelegate* delegate); - GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, bool render_to_surface); + GPUSurfaceGLSkia(GPUSurfaceGLDelegate* delegate, bool render_to_surface); // Creates a new GL surface reusing an existing GrDirectContext. - GPUSurfaceGL(sk_sp gr_context, - GPUSurfaceGLDelegate* delegate, - bool render_to_surface); + GPUSurfaceGLSkia(sk_sp gr_context, + GPUSurfaceGLDelegate* delegate, + bool render_to_surface); // |Surface| - ~GPUSurfaceGL() override; + ~GPUSurfaceGLSkia() override; // |Surface| bool IsValid() override; @@ -76,10 +76,10 @@ class GPUSurfaceGL : public Surface { bool valid_ = false; // WeakPtrFactory must be the last member. - fml::TaskRunnerAffineWeakPtrFactory weak_factory_; - FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGL); + fml::TaskRunnerAffineWeakPtrFactory weak_factory_; + FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGLSkia); }; } // namespace flutter -#endif // SHELL_GPU_GPU_SURFACE_GL_H_ +#endif // SHELL_GPU_GPU_SURFACE_GL_SKIA_H_ diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index a12c8dfee38..f18bb672e72 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -64,18 +64,24 @@ source_set("flutter_shell_native_src") { "$root_build_dir/flutter_icu/icudtl.o", "android_choreographer.cc", "android_choreographer.h", - "android_context_gl.cc", - "android_context_gl.h", + "android_context_gl_impeller.cc", + "android_context_gl_impeller.h", + "android_context_gl_skia.cc", + "android_context_gl_skia.h", "android_display.cc", "android_display.h", + "android_egl_surface.cc", + "android_egl_surface.h", "android_environment_gl.cc", "android_environment_gl.h", "android_external_texture_gl.cc", "android_external_texture_gl.h", "android_shell_holder.cc", "android_shell_holder.h", - "android_surface_gl.cc", - "android_surface_gl.h", + "android_surface_gl_impeller.cc", + "android_surface_gl_impeller.h", + "android_surface_gl_skia.cc", + "android_surface_gl_skia.h", "android_surface_software.cc", "android_surface_software.h", "apk_asset_provider.cc", @@ -104,6 +110,8 @@ source_set("flutter_shell_native_src") { "//flutter/common/graphics", "//flutter/flow", "//flutter/fml", + "//flutter/impeller", + "//flutter/impeller/toolkit/egl", "//flutter/lib/ui", "//flutter/runtime", "//flutter/runtime:libdart", diff --git a/engine/src/flutter/shell/platform/android/android_context_gl.h b/engine/src/flutter/shell/platform/android/android_context_gl.h deleted file mode 100644 index db130bcd089..00000000000 --- a/engine/src/flutter/shell/platform/android/android_context_gl.h +++ /dev/null @@ -1,186 +0,0 @@ -// 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_ANDROID_ANDROID_CONTEXT_GL_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_H_ - -#include "flutter/fml/macros.h" -#include "flutter/fml/memory/ref_counted.h" -#include "flutter/fml/memory/ref_ptr.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/platform/android/android_environment_gl.h" -#include "flutter/shell/platform/android/context/android_context.h" -#include "flutter/shell/platform/android/surface/android_native_window.h" -#include "third_party/skia/include/core/SkSize.h" - -namespace flutter { - -//------------------------------------------------------------------------------ -/// Holds an `EGLSurface` reference. -/// -/// -/// This can be used in conjunction to unique_ptr to provide better guarantees -/// about the lifespan of the `EGLSurface` object. -/// -class AndroidEGLSurfaceDamage; - -/// Result of calling MakeCurrent on AndroidEGLSurface. -enum class AndroidEGLSurfaceMakeCurrentStatus { - /// Success, the egl context for the surface was already current. - kSuccessAlreadyCurrent, - /// Success, the egl context for the surface made current. - kSuccessMadeCurrent, - /// Failed to make the egl context for the surface current. - kFailure, -}; - -class AndroidEGLSurface { - public: - AndroidEGLSurface(EGLSurface surface, EGLDisplay display, EGLContext context); - ~AndroidEGLSurface(); - - //---------------------------------------------------------------------------- - /// @return Whether the current `EGLSurface` reference is valid. That is, - /// if - /// the surface doesn't point to `EGL_NO_SURFACE`. - /// - bool IsValid() const; - - //---------------------------------------------------------------------------- - /// @brief Binds the EGLContext context to the current rendering thread - /// and to the draw and read surface. - /// - /// @return Whether the surface was made current. - /// - AndroidEGLSurfaceMakeCurrentStatus MakeCurrent() const; - - //---------------------------------------------------------------------------- - /// - /// @return Whether target surface supports partial repaint. - /// - bool SupportsPartialRepaint() const; - - //---------------------------------------------------------------------------- - /// @brief This is the minimal area that needs to be repainted to get - /// correct result. - /// - /// With double or triple buffering this buffer content may lag behind - /// current front buffer and the rect accounts for accumulated damage. - /// - /// @return The area of current surface where it is behind front buffer. - /// - std::optional InitialDamage(); - - //---------------------------------------------------------------------------- - /// @brief Sets the damage region for current surface. Corresponds to - // eglSetDamageRegionKHR - void SetDamageRegion(const std::optional& buffer_damage); - - //---------------------------------------------------------------------------- - /// @brief This only applies to on-screen surfaces such as those created - /// by `AndroidContextGL::CreateOnscreenSurface`. - /// - /// @return Whether the EGL surface color buffer was swapped. - /// - bool SwapBuffers(const std::optional& surface_damage); - - //---------------------------------------------------------------------------- - /// @return The size of an `EGLSurface`. - /// - SkISize GetSize() const; - - private: - /// Returns true if the EGLContext held is current for the display and surface - bool IsContextCurrent() const; - - const EGLSurface surface_; - const EGLDisplay display_; - const EGLContext context_; - std::unique_ptr damage_; -}; - -//------------------------------------------------------------------------------ -/// The Android context is used by `AndroidSurfaceGL` to create and manage -/// EGL surfaces. -/// -/// This context binds `EGLContext` to the current rendering thread and to the -/// draw and read `EGLSurface`s. -/// -class AndroidContextGL : public AndroidContext { - public: - AndroidContextGL(AndroidRenderingAPI rendering_api, - fml::RefPtr environment, - const TaskRunners& taskRunners, - uint8_t msaa_samples); - - ~AndroidContextGL(); - - //---------------------------------------------------------------------------- - /// @brief Allocates an new EGL window surface that is used for on-screen - /// pixels. - /// - /// @return The window surface. - /// - std::unique_ptr CreateOnscreenSurface( - fml::RefPtr window) const; - - //---------------------------------------------------------------------------- - /// @brief Allocates an 1x1 pbuffer surface that is used for making the - /// offscreen current for texture uploads. - /// - /// @return The pbuffer surface. - /// - std::unique_ptr CreateOffscreenSurface() const; - - //---------------------------------------------------------------------------- - /// @brief Allocates an 1x1 pbuffer surface that is used for making the - /// onscreen context current for snapshotting. - /// - /// @return The pbuffer surface. - /// - std::unique_ptr CreatePbufferSurface() const; - - //---------------------------------------------------------------------------- - /// @return The Android environment that contains a reference to the - /// display. - /// - fml::RefPtr Environment() const; - - //---------------------------------------------------------------------------- - /// @return Whether the current context is valid. That is, if the EGL - /// contexts were successfully created. - /// - bool IsValid() const override; - - //---------------------------------------------------------------------------- - /// @return Whether the current context was successfully clear. - /// - bool ClearCurrent() const; - - //---------------------------------------------------------------------------- - /// @brief Create a new EGLContext using the same EGLConfig. - /// - /// @return The EGLContext. - /// - EGLContext CreateNewContext() const; - - //---------------------------------------------------------------------------- - /// @brief The EGLConfig for this context. - /// - EGLConfig Config() const { return config_; } - - private: - fml::RefPtr environment_; - EGLConfig config_; - EGLContext context_; - EGLContext resource_context_; - bool valid_ = false; - TaskRunners task_runners_; - - FML_DISALLOW_COPY_AND_ASSIGN(AndroidContextGL); -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_H_ diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc new file mode 100644 index 00000000000..ff4f59a576f --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc @@ -0,0 +1,18 @@ +// 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/android/android_context_gl_impeller.h" + +namespace flutter { + +AndroidContextGLImpeller::AndroidContextGLImpeller() + : AndroidContext(AndroidRenderingAPI::kOpenGLES) {} + +AndroidContextGLImpeller::~AndroidContextGLImpeller() = default; + +bool AndroidContextGLImpeller::IsValid() const { + return true; +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_impeller.h b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.h new file mode 100644 index 00000000000..51e9f7b1284 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.h @@ -0,0 +1,28 @@ +// 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_ANDROID_ANDROID_CONTEXT_GL_IMPELLER_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_IMPELLER_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/android/context/android_context.h" + +namespace flutter { + +class AndroidContextGLImpeller : public AndroidContext { + public: + AndroidContextGLImpeller(); + + ~AndroidContextGLImpeller(); + + // |AndroidContext| + bool IsValid() const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(AndroidContextGLImpeller); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_IMPELLER_H_ diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_skia.cc b/engine/src/flutter/shell/platform/android/android_context_gl_skia.cc new file mode 100644 index 00000000000..1af21c40cde --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_context_gl_skia.cc @@ -0,0 +1,216 @@ +// 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/android/android_context_gl_skia.h" + +#include + +#include "flutter/fml/trace_event.h" +#include "flutter/shell/platform/android/android_egl_surface.h" + +namespace flutter { + +template +using EGLResult = std::pair; + +static EGLResult CreateContext(EGLDisplay display, + EGLConfig config, + EGLContext share = EGL_NO_CONTEXT) { + EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + + EGLContext context = eglCreateContext(display, config, share, attributes); + + return {context != EGL_NO_CONTEXT, context}; +} + +static EGLResult ChooseEGLConfiguration(EGLDisplay display, + uint8_t msaa_samples) { + EGLint sample_buffers = msaa_samples > 1 ? 1 : 0; + EGLint attributes[] = { + // clang-format off + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLES, static_cast(msaa_samples), + EGL_SAMPLE_BUFFERS, sample_buffers, + EGL_NONE, // termination sentinel + // clang-format on + }; + + EGLint config_count = 0; + EGLConfig egl_config = nullptr; + + if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) != + EGL_TRUE) { + return {false, nullptr}; + } + + bool success = config_count > 0 && egl_config != nullptr; + + return {success, success ? egl_config : nullptr}; +} + +static bool TeardownContext(EGLDisplay display, EGLContext context) { + if (context != EGL_NO_CONTEXT) { + return eglDestroyContext(display, context) == EGL_TRUE; + } + + return true; +} + +AndroidContextGLSkia::AndroidContextGLSkia( + AndroidRenderingAPI rendering_api, + fml::RefPtr environment, + const TaskRunners& task_runners, + uint8_t msaa_samples) + : AndroidContext(AndroidRenderingAPI::kOpenGLES), + environment_(environment), + config_(nullptr), + task_runners_(task_runners) { + if (!environment_->IsValid()) { + FML_LOG(ERROR) << "Could not create an Android GL environment."; + return; + } + + bool success = false; + + // Choose a valid configuration. + std::tie(success, config_) = + ChooseEGLConfiguration(environment_->Display(), msaa_samples); + if (!success) { + FML_LOG(ERROR) << "Could not choose an EGL configuration."; + LogLastEGLError(); + return; + } + + // Create a context for the configuration. + std::tie(success, context_) = + CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT); + if (!success) { + FML_LOG(ERROR) << "Could not create an EGL context"; + LogLastEGLError(); + return; + } + + std::tie(success, resource_context_) = + CreateContext(environment_->Display(), config_, context_); + if (!success) { + FML_LOG(ERROR) << "Could not create an EGL resource context"; + LogLastEGLError(); + return; + } + + // All done! + valid_ = true; +} + +AndroidContextGLSkia::~AndroidContextGLSkia() { + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + sk_sp main_context = GetMainSkiaContext(); + SetMainSkiaContext(nullptr); + fml::AutoResetWaitableEvent latch; + // This context needs to be deallocated from the raster thread in order to + // keep a coherent usage of egl from a single thread. + fml::TaskRunner::RunNowOrPostTask(task_runners_.GetRasterTaskRunner(), [&] { + if (main_context) { + std::unique_ptr pbuffer_surface = + CreatePbufferSurface(); + auto status = pbuffer_surface->MakeCurrent(); + if (status != AndroidEGLSurfaceMakeCurrentStatus::kFailure) { + main_context->releaseResourcesAndAbandonContext(); + main_context.reset(); + ClearCurrent(); + } + } + latch.Signal(); + }); + latch.Wait(); + + if (!TeardownContext(environment_->Display(), context_)) { + FML_LOG(ERROR) + << "Could not tear down the EGL context. Possible resource leak."; + LogLastEGLError(); + } + + if (!TeardownContext(environment_->Display(), resource_context_)) { + FML_LOG(ERROR) << "Could not tear down the EGL resource context. Possible " + "resource leak."; + LogLastEGLError(); + } +} + +std::unique_ptr AndroidContextGLSkia::CreateOnscreenSurface( + fml::RefPtr window) const { + if (window->IsFakeWindow()) { + return CreatePbufferSurface(); + } else { + EGLDisplay display = environment_->Display(); + + const EGLint attribs[] = {EGL_NONE}; + + EGLSurface surface = eglCreateWindowSurface( + display, config_, + reinterpret_cast(window->handle()), attribs); + return std::make_unique(surface, display, context_); + } +} + +std::unique_ptr +AndroidContextGLSkia::CreateOffscreenSurface() const { + // We only ever create pbuffer surfaces for background resource loading + // contexts. We never bind the pbuffer to anything. + EGLDisplay display = environment_->Display(); + + const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + + EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); + return std::make_unique(surface, display, + resource_context_); +} + +std::unique_ptr AndroidContextGLSkia::CreatePbufferSurface() + const { + EGLDisplay display = environment_->Display(); + + const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + + EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); + return std::make_unique(surface, display, context_); +} + +fml::RefPtr AndroidContextGLSkia::Environment() const { + return environment_; +} + +bool AndroidContextGLSkia::IsValid() const { + return valid_; +} + +bool AndroidContextGLSkia::ClearCurrent() const { + if (eglGetCurrentContext() != context_) { + return true; + } + if (eglMakeCurrent(environment_->Display(), EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT) != EGL_TRUE) { + FML_LOG(ERROR) << "Could not clear the current context"; + LogLastEGLError(); + return false; + } + return true; +} + +EGLContext AndroidContextGLSkia::CreateNewContext() const { + bool success; + EGLContext context; + std::tie(success, context) = + CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT); + return success ? context : EGL_NO_CONTEXT; +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_skia.h b/engine/src/flutter/shell/platform/android/android_context_gl_skia.h new file mode 100644 index 00000000000..f3e9ff9f2ef --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_context_gl_skia.h @@ -0,0 +1,104 @@ +// 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_ANDROID_ANDROID_CONTEXT_GL_SKIA_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_SKIA_H_ + +#include "flutter/fml/macros.h" +#include "flutter/fml/memory/ref_counted.h" +#include "flutter/fml/memory/ref_ptr.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/platform/android/android_environment_gl.h" +#include "flutter/shell/platform/android/context/android_context.h" +#include "flutter/shell/platform/android/surface/android_native_window.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace flutter { + +class AndroidEGLSurface; + +//------------------------------------------------------------------------------ +/// The Android context is used by `AndroidSurfaceGL` to create and manage +/// EGL surfaces. +/// +/// This context binds `EGLContext` to the current rendering thread and to the +/// draw and read `EGLSurface`s. +/// +class AndroidContextGLSkia : public AndroidContext { + public: + AndroidContextGLSkia(AndroidRenderingAPI rendering_api, + fml::RefPtr environment, + const TaskRunners& taskRunners, + uint8_t msaa_samples); + + ~AndroidContextGLSkia(); + + //---------------------------------------------------------------------------- + /// @brief Allocates an new EGL window surface that is used for on-screen + /// pixels. + /// + /// @return The window surface. + /// + std::unique_ptr CreateOnscreenSurface( + fml::RefPtr window) const; + + //---------------------------------------------------------------------------- + /// @brief Allocates an 1x1 pbuffer surface that is used for making the + /// offscreen current for texture uploads. + /// + /// @return The pbuffer surface. + /// + std::unique_ptr CreateOffscreenSurface() const; + + //---------------------------------------------------------------------------- + /// @brief Allocates an 1x1 pbuffer surface that is used for making the + /// onscreen context current for snapshotting. + /// + /// @return The pbuffer surface. + /// + std::unique_ptr CreatePbufferSurface() const; + + //---------------------------------------------------------------------------- + /// @return The Android environment that contains a reference to the + /// display. + /// + fml::RefPtr Environment() const; + + //---------------------------------------------------------------------------- + /// @return Whether the current context is valid. That is, if the EGL + /// contexts were successfully created. + /// + bool IsValid() const override; + + //---------------------------------------------------------------------------- + /// @return Whether the current context was successfully clear. + /// + bool ClearCurrent() const; + + //---------------------------------------------------------------------------- + /// @brief Create a new EGLContext using the same EGLConfig. + /// + /// @return The EGLContext. + /// + EGLContext CreateNewContext() const; + + //---------------------------------------------------------------------------- + /// @brief The EGLConfig for this context. + /// + EGLConfig Config() const { return config_; } + + private: + fml::RefPtr environment_; + EGLConfig config_; + EGLContext context_; + EGLContext resource_context_; + bool valid_ = false; + TaskRunners task_runners_; + + FML_DISALLOW_COPY_AND_ASSIGN(AndroidContextGLSkia); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_SKIA_H_ diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc b/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc index 2491886b7b5..6edb19ff506 100644 --- a/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc +++ b/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc @@ -2,9 +2,10 @@ #include #include "flutter/shell/common/thread_host.h" -#include "flutter/shell/platform/android/android_context_gl.h" +#include "flutter/shell/platform/android/android_context_gl_skia.h" +#include "flutter/shell/platform/android/android_egl_surface.h" #include "flutter/shell/platform/android/android_environment_gl.h" -#include "flutter/shell/platform/android/android_surface_gl.h" +#include "flutter/shell/platform/android/android_surface_gl_skia.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -85,7 +86,7 @@ TEST(AndroidContextGl, Create) { thread_label, ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); - auto context = std::make_unique( + auto context = std::make_unique( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0); context->SetMainSkiaContext(main_context); EXPECT_NE(context.get(), nullptr); @@ -106,7 +107,7 @@ TEST(AndroidContextGl, CreateSingleThread) { TaskRunners task_runners = TaskRunners(thread_label, platform_runner, platform_runner, platform_runner, platform_runner); - auto context = std::make_unique( + auto context = std::make_unique( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0); context->SetMainSkiaContext(main_context); EXPECT_NE(context.get(), nullptr); @@ -125,11 +126,11 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNotNull) { thread_label, ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); - auto android_context = std::make_shared( + auto android_context = std::make_shared( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0); auto jni = std::make_shared(); auto android_surface = - std::make_unique(android_context, jni); + std::make_unique(android_context, jni); auto window = fml::MakeRefCounted( nullptr, /*is_fake_window=*/true); android_surface->SetNativeWindow(window); @@ -153,11 +154,11 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNull) { ThreadHost thread_host(host_config); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); - auto android_context = std::make_shared( + auto android_context = std::make_shared( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0); auto jni = std::make_shared(); auto android_surface = - std::make_unique(android_context, jni); + std::make_unique(android_context, jni); EXPECT_EQ(android_surface->GetOnscreenSurface(), nullptr); android_surface->CreateSnapshotSurface(); EXPECT_NE(android_surface->GetOnscreenSurface(), nullptr); @@ -175,7 +176,7 @@ TEST(AndroidContextGl, MSAAx4) { thread_label, ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); - auto context = std::make_unique( + auto context = std::make_unique( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 4); context->SetMainSkiaContext(main_context); @@ -197,7 +198,7 @@ TEST(AndroidContextGl, EnsureMakeCurrentChecksCurrentContextStatus) { thread_label, ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); - auto context = std::make_unique( + auto context = std::make_unique( AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0); auto pbuffer_surface = context->CreatePbufferSurface(); diff --git a/engine/src/flutter/shell/platform/android/android_context_gl.cc b/engine/src/flutter/shell/platform/android/android_egl_surface.cc similarity index 55% rename from engine/src/flutter/shell/platform/android/android_context_gl.cc rename to engine/src/flutter/shell/platform/android/android_egl_surface.cc index f1257e66322..3f02d35e3be 100644 --- a/engine/src/flutter/shell/platform/android/android_context_gl.cc +++ b/engine/src/flutter/shell/platform/android/android_egl_surface.cc @@ -2,31 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/android/android_context_gl.h" +#include "flutter/shell/platform/android/android_egl_surface.h" #include - -#include -#include - -// required to get API level #include +#include +#include + #include "flutter/fml/trace_event.h" namespace flutter { -template -using EGLResult = std::pair; - -static void LogLastEGLError() { +void LogLastEGLError() { struct EGLNameErrorPair { const char* name; EGLint code; }; #define _EGL_ERROR_DESC(a) \ - { #a, a } + { \ +#a, a \ + } const EGLNameErrorPair pairs[] = { _EGL_ERROR_DESC(EGL_SUCCESS), @@ -63,56 +60,6 @@ static void LogLastEGLError() { FML_LOG(ERROR) << "Unknown EGL Error"; } -static EGLResult CreateContext(EGLDisplay display, - EGLConfig config, - EGLContext share = EGL_NO_CONTEXT) { - EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - - EGLContext context = eglCreateContext(display, config, share, attributes); - - return {context != EGL_NO_CONTEXT, context}; -} - -static EGLResult ChooseEGLConfiguration(EGLDisplay display, - uint8_t msaa_samples) { - EGLint sample_buffers = msaa_samples > 1 ? 1 : 0; - EGLint attributes[] = { - // clang-format off - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, 0, - EGL_SAMPLES, static_cast(msaa_samples), - EGL_SAMPLE_BUFFERS, sample_buffers, - EGL_NONE, // termination sentinel - // clang-format on - }; - - EGLint config_count = 0; - EGLConfig egl_config = nullptr; - - if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) != - EGL_TRUE) { - return {false, nullptr}; - } - - bool success = config_count > 0 && egl_config != nullptr; - - return {success, success ? egl_config : nullptr}; -} - -static bool TeardownContext(EGLDisplay display, EGLContext context) { - if (context != EGL_NO_CONTEXT) { - return eglDestroyContext(display, context) == EGL_TRUE; - } - - return true; -} - class AndroidEGLSurfaceDamage { public: void init(EGLDisplay display, EGLContext context) { @@ -320,153 +267,4 @@ SkISize AndroidEGLSurface::GetSize() const { return SkISize::Make(width, height); } -AndroidContextGL::AndroidContextGL( - AndroidRenderingAPI rendering_api, - fml::RefPtr environment, - const TaskRunners& task_runners, - uint8_t msaa_samples) - : AndroidContext(AndroidRenderingAPI::kOpenGLES), - environment_(environment), - config_(nullptr), - task_runners_(task_runners) { - if (!environment_->IsValid()) { - FML_LOG(ERROR) << "Could not create an Android GL environment."; - return; - } - - bool success = false; - - // Choose a valid configuration. - std::tie(success, config_) = - ChooseEGLConfiguration(environment_->Display(), msaa_samples); - if (!success) { - FML_LOG(ERROR) << "Could not choose an EGL configuration."; - LogLastEGLError(); - return; - } - - // Create a context for the configuration. - std::tie(success, context_) = - CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT); - if (!success) { - FML_LOG(ERROR) << "Could not create an EGL context"; - LogLastEGLError(); - return; - } - - std::tie(success, resource_context_) = - CreateContext(environment_->Display(), config_, context_); - if (!success) { - FML_LOG(ERROR) << "Could not create an EGL resource context"; - LogLastEGLError(); - return; - } - - // All done! - valid_ = true; -} - -AndroidContextGL::~AndroidContextGL() { - FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - sk_sp main_context = GetMainSkiaContext(); - SetMainSkiaContext(nullptr); - fml::AutoResetWaitableEvent latch; - // This context needs to be deallocated from the raster thread in order to - // keep a coherent usage of egl from a single thread. - fml::TaskRunner::RunNowOrPostTask(task_runners_.GetRasterTaskRunner(), [&] { - if (main_context) { - std::unique_ptr pbuffer_surface = - CreatePbufferSurface(); - auto status = pbuffer_surface->MakeCurrent(); - if (status != AndroidEGLSurfaceMakeCurrentStatus::kFailure) { - main_context->releaseResourcesAndAbandonContext(); - main_context.reset(); - ClearCurrent(); - } - } - latch.Signal(); - }); - latch.Wait(); - - if (!TeardownContext(environment_->Display(), context_)) { - FML_LOG(ERROR) - << "Could not tear down the EGL context. Possible resource leak."; - LogLastEGLError(); - } - - if (!TeardownContext(environment_->Display(), resource_context_)) { - FML_LOG(ERROR) << "Could not tear down the EGL resource context. Possible " - "resource leak."; - LogLastEGLError(); - } -} - -std::unique_ptr AndroidContextGL::CreateOnscreenSurface( - fml::RefPtr window) const { - if (window->IsFakeWindow()) { - return CreatePbufferSurface(); - } else { - EGLDisplay display = environment_->Display(); - - const EGLint attribs[] = {EGL_NONE}; - - EGLSurface surface = eglCreateWindowSurface( - display, config_, - reinterpret_cast(window->handle()), attribs); - return std::make_unique(surface, display, context_); - } -} - -std::unique_ptr AndroidContextGL::CreateOffscreenSurface() - const { - // We only ever create pbuffer surfaces for background resource loading - // contexts. We never bind the pbuffer to anything. - EGLDisplay display = environment_->Display(); - - const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - - EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); - return std::make_unique(surface, display, - resource_context_); -} - -std::unique_ptr AndroidContextGL::CreatePbufferSurface() - const { - EGLDisplay display = environment_->Display(); - - const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - - EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); - return std::make_unique(surface, display, context_); -} - -fml::RefPtr AndroidContextGL::Environment() const { - return environment_; -} - -bool AndroidContextGL::IsValid() const { - return valid_; -} - -bool AndroidContextGL::ClearCurrent() const { - if (eglGetCurrentContext() != context_) { - return true; - } - if (eglMakeCurrent(environment_->Display(), EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT) != EGL_TRUE) { - FML_LOG(ERROR) << "Could not clear the current context"; - LogLastEGLError(); - return false; - } - return true; -} - -EGLContext AndroidContextGL::CreateNewContext() const { - bool success; - EGLContext context; - std::tie(success, context) = - CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT); - return success ? context : EGL_NO_CONTEXT; -} - } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/android_egl_surface.h b/engine/src/flutter/shell/platform/android/android_egl_surface.h new file mode 100644 index 00000000000..4b49c1b0ed6 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_egl_surface.h @@ -0,0 +1,105 @@ +// 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_ANDROID_ANDROID_EGL_SURFACE_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_EGL_SURFACE_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/android/android_environment_gl.h" +#include "third_party/skia/include/core/SkRect.h" + +namespace flutter { + +//------------------------------------------------------------------------------ +/// Holds an `EGLSurface` reference. +/// +/// +/// This can be used in conjunction to unique_ptr to provide better guarantees +/// about the lifespan of the `EGLSurface` object. +/// +class AndroidEGLSurfaceDamage; + +/// Result of calling MakeCurrent on AndroidEGLSurface. +enum class AndroidEGLSurfaceMakeCurrentStatus { + /// Success, the egl context for the surface was already current. + kSuccessAlreadyCurrent, + /// Success, the egl context for the surface made current. + kSuccessMadeCurrent, + /// Failed to make the egl context for the surface current. + kFailure, +}; + +void LogLastEGLError(); + +class AndroidEGLSurface { + public: + AndroidEGLSurface(EGLSurface surface, EGLDisplay display, EGLContext context); + + ~AndroidEGLSurface(); + + //---------------------------------------------------------------------------- + /// @return Whether the current `EGLSurface` reference is valid. That is, + /// if + /// the surface doesn't point to `EGL_NO_SURFACE`. + /// + bool IsValid() const; + + //---------------------------------------------------------------------------- + /// @brief Binds the EGLContext context to the current rendering thread + /// and to the draw and read surface. + /// + /// @return Whether the surface was made current. + /// + AndroidEGLSurfaceMakeCurrentStatus MakeCurrent() const; + + //---------------------------------------------------------------------------- + /// + /// @return Whether target surface supports partial repaint. + /// + bool SupportsPartialRepaint() const; + + //---------------------------------------------------------------------------- + /// @brief This is the minimal area that needs to be repainted to get + /// correct result. + /// + /// With double or triple buffering this buffer content may lag behind + /// current front buffer and the rect accounts for accumulated damage. + /// + /// @return The area of current surface where it is behind front buffer. + /// + std::optional InitialDamage(); + + //---------------------------------------------------------------------------- + /// @brief Sets the damage region for current surface. Corresponds to + // eglSetDamageRegionKHR + void SetDamageRegion(const std::optional& buffer_damage); + + //---------------------------------------------------------------------------- + /// @brief This only applies to on-screen surfaces such as those created + /// by `AndroidContextGL::CreateOnscreenSurface`. + /// + /// @return Whether the EGL surface color buffer was swapped. + /// + bool SwapBuffers(const std::optional& surface_damage); + + //---------------------------------------------------------------------------- + /// @return The size of an `EGLSurface`. + /// + SkISize GetSize() const; + + private: + /// Returns true if the EGLContext held is current for the display and surface + bool IsContextCurrent() const; + + const EGLSurface surface_; + const EGLDisplay display_; + const EGLContext context_; + std::unique_ptr damage_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_EGL_SURFACE_H_ diff --git a/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.cc b/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.cc new file mode 100644 index 00000000000..8c4ab3d4742 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.cc @@ -0,0 +1,263 @@ +// 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/android/android_surface_gl_impeller.h" + +#include "flutter/fml/logging.h" +#include "flutter/impeller/entity/gles/entity_shaders_gles.h" +#include "flutter/impeller/renderer/backend/gles/context_gles.h" +#include "flutter/impeller/renderer/backend/gles/proc_table_gles.h" +#include "flutter/impeller/toolkit/egl/context.h" +#include "flutter/impeller/toolkit/egl/surface.h" +#include "flutter/shell/gpu/gpu_surface_gl_impeller.h" + +namespace flutter { + +static std::shared_ptr CreateImpellerContext() { + auto proc_table = std::make_unique( + impeller::egl::CreateProcAddressResolver()); + + if (!proc_table->IsValid()) { + FML_LOG(ERROR) << "Could not create OpenGL proc table."; + return nullptr; + } + + std::vector> shader_mappings = { + std::make_shared( + impeller_entity_shaders_gles_data, + impeller_entity_shaders_gles_length), + }; + + auto context = + impeller::ContextGLES::Create(std::move(proc_table), shader_mappings); + if (!context) { + FML_LOG(ERROR) << "Could not create OpenGLES Impeller Context."; + return nullptr; + } + return context; +} + +AndroidSurfaceGLImpeller::AndroidSurfaceGLImpeller( + const std::shared_ptr& android_context, + std::shared_ptr jni_facade) + : AndroidSurface(android_context) { + auto display = std::make_unique(); + if (!display->IsValid()) { + FML_DLOG(ERROR) << "Could not create EGL display."; + return; + } + + impeller::egl::ConfigDescriptor desc; + desc.api = impeller::egl::API::kOpenGLES2; + desc.color_format = impeller::egl::ColorFormat::kRGBA8888; + desc.depth_bits = impeller::egl::DepthBits::kZero; + desc.stencil_bits = impeller::egl::StencilBits::kEight; + desc.samples = impeller::egl::Samples::kFour; + + desc.surface_type = impeller::egl::SurfaceType::kWindow; + auto onscreen_config = display->ChooseConfig(desc); + if (!onscreen_config) { + FML_DLOG(ERROR) << "Could not choose onscreen config."; + return; + } + + desc.surface_type = impeller::egl::SurfaceType::kPBuffer; + auto offscreen_config = display->ChooseConfig(desc); + if (!offscreen_config) { + FML_DLOG(ERROR) << "Could not choose offscreen config."; + return; + } + + auto onscreen_context = display->CreateContext(*onscreen_config, nullptr); + if (!onscreen_context) { + FML_DLOG(ERROR) << "Could not create onscreen context."; + return; + } + + auto offscreen_context = + display->CreateContext(*offscreen_config, onscreen_context.get()); + if (!offscreen_context) { + FML_DLOG(ERROR) << "Could not create offscreen context."; + return; + } + + auto offscreen_surface = + display->CreatePixelBufferSurface(*offscreen_config, 1u, 1u); + if (!offscreen_surface) { + FML_DLOG(ERROR) << "Could not create offscreen surface."; + return; + } + + if (!offscreen_context->MakeCurrent(*offscreen_surface)) { + FML_DLOG(ERROR) << "Could not make offscreen context current."; + return; + } + + auto impeller_context = CreateImpellerContext(); + + if (!impeller_context) { + FML_DLOG(ERROR) << "Could not create Impeller context."; + return; + } + + if (!offscreen_context->ClearCurrent()) { + FML_DLOG(ERROR) << "Could not clear offscreen context."; + return; + } + + display_ = std::move(display); + onscreen_config_ = std::move(onscreen_config); + offscreen_config_ = std::move(offscreen_config); + offscreen_surface_ = std::move(offscreen_surface); + onscreen_context_ = std::move(onscreen_context); + offscreen_context_ = std::move(offscreen_context); + impeller_context_ = std::move(impeller_context); + + // The onscreen surface will be acquired once the native window is set. + + is_valid_ = true; +} + +AndroidSurfaceGLImpeller::~AndroidSurfaceGLImpeller() = default; + +// |AndroidSurface| +bool AndroidSurfaceGLImpeller::IsValid() const { + return is_valid_; +} + +// |AndroidSurface| +std::unique_ptr AndroidSurfaceGLImpeller::CreateGPUSurface( + GrDirectContext* gr_context) { + auto surface = + std::make_unique(this, // delegate + impeller_context_ // context + ); + if (!surface->IsValid()) { + return nullptr; + } + return surface; +} + +// |AndroidSurface| +void AndroidSurfaceGLImpeller::TeardownOnScreenContext() { + GLContextClearCurrent(); + onscreen_surface_.reset(); +} + +// |AndroidSurface| +bool AndroidSurfaceGLImpeller::OnScreenSurfaceResize(const SkISize& size) { + // The size is unused. It was added only for iOS where the sizes were + // necessary to re-create auxiliary buffers (stencil, depth, etc.). + return RecreateOnscreenSurfaceAndMakeOnscreenContextCurrent(); +} + +// |AndroidSurface| +bool AndroidSurfaceGLImpeller::ResourceContextMakeCurrent() { + if (!offscreen_context_ || !offscreen_surface_) { + return false; + } + + return offscreen_context_->MakeCurrent(*offscreen_surface_); +} + +// |AndroidSurface| +bool AndroidSurfaceGLImpeller::ResourceContextClearCurrent() { + if (!offscreen_context_ || !offscreen_surface_) { + return false; + } + + return offscreen_context_->ClearCurrent(); +} + +// |AndroidSurface| +bool AndroidSurfaceGLImpeller::SetNativeWindow( + fml::RefPtr window) { + native_window_ = std::move(window); + return RecreateOnscreenSurfaceAndMakeOnscreenContextCurrent(); +} + +// |AndroidSurface| +std::unique_ptr AndroidSurfaceGLImpeller::CreateSnapshotSurface() { + FML_UNREACHABLE(); +} + +// |GPUSurfaceGLDelegate| +std::unique_ptr +AndroidSurfaceGLImpeller::GLContextMakeCurrent() { + return std::make_unique(OnGLContextMakeCurrent()); +} + +bool AndroidSurfaceGLImpeller::OnGLContextMakeCurrent() { + if (!onscreen_surface_ || !onscreen_context_) { + return false; + } + + return onscreen_context_->MakeCurrent(*onscreen_surface_); +} + +// |GPUSurfaceGLDelegate| +bool AndroidSurfaceGLImpeller::GLContextClearCurrent() { + if (!onscreen_surface_ || !onscreen_context_) { + return false; + } + + return onscreen_context_->ClearCurrent(); +} + +// |GPUSurfaceGLDelegate| +SurfaceFrame::FramebufferInfo +AndroidSurfaceGLImpeller::GLContextFramebufferInfo() const { + auto info = SurfaceFrame::FramebufferInfo{}; + info.supports_readback = true; + info.supports_partial_repaint = false; + return info; +} + +// |GPUSurfaceGLDelegate| +void AndroidSurfaceGLImpeller::GLContextSetDamageRegion( + const std::optional& region) { + // Not supported. +} + +// |GPUSurfaceGLDelegate| +bool AndroidSurfaceGLImpeller::GLContextPresent( + uint32_t fbo_id, + const std::optional& damage) { + // The FBO ID is superfluous and was introduced for iOS where the default + // framebuffer was not FBO0. + if (!onscreen_surface_) { + return false; + } + return onscreen_surface_->Present(); +} + +// |GPUSurfaceGLDelegate| +intptr_t AndroidSurfaceGLImpeller::GLContextFBO(GLFrameInfo frame_info) const { + // FBO0 is the default window bound framebuffer in EGL environments. + return 0; +} + +// |GPUSurfaceGLDelegate| +sk_sp AndroidSurfaceGLImpeller::GetGLInterface() const { + return nullptr; +} + +bool AndroidSurfaceGLImpeller:: + RecreateOnscreenSurfaceAndMakeOnscreenContextCurrent() { + GLContextClearCurrent(); + if (!native_window_) { + return false; + } + onscreen_surface_.reset(); + auto onscreen_surface = display_->CreateWindowSurface( + *onscreen_config_, native_window_->handle()); + if (!onscreen_surface) { + FML_DLOG(ERROR) << "Could not create onscreen surface."; + return false; + } + onscreen_surface_ = std::move(onscreen_surface); + return OnGLContextMakeCurrent(); +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.h b/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.h new file mode 100644 index 00000000000..187414c49d9 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/android_surface_gl_impeller.h @@ -0,0 +1,96 @@ +// 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_ANDROID_ANDROID_SURFACE_GL_IMPELLER_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_IMPELLER_H_ + +#include "flutter/fml/macros.h" +#include "flutter/impeller/renderer/context.h" +#include "flutter/impeller/toolkit/egl/display.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" +#include "flutter/shell/platform/android/surface/android_native_window.h" +#include "flutter/shell/platform/android/surface/android_surface.h" + +namespace flutter { + +class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate, + public AndroidSurface { + public: + AndroidSurfaceGLImpeller( + const std::shared_ptr& android_context, + std::shared_ptr jni_facade); + + // |AndroidSurface| + ~AndroidSurfaceGLImpeller() override; + + // |AndroidSurface| + bool IsValid() const override; + + // |AndroidSurface| + std::unique_ptr CreateGPUSurface( + GrDirectContext* gr_context) override; + + // |AndroidSurface| + void TeardownOnScreenContext() override; + + // |AndroidSurface| + bool OnScreenSurfaceResize(const SkISize& size) override; + + // |AndroidSurface| + bool ResourceContextMakeCurrent() override; + + // |AndroidSurface| + bool ResourceContextClearCurrent() override; + + // |AndroidSurface| + bool SetNativeWindow(fml::RefPtr window) override; + + // |AndroidSurface| + std::unique_ptr CreateSnapshotSurface() override; + + // |GPUSurfaceGLDelegate| + std::unique_ptr GLContextMakeCurrent() override; + + // |GPUSurfaceGLDelegate| + bool GLContextClearCurrent() override; + + // |GPUSurfaceGLDelegate| + SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override; + + // |GPUSurfaceGLDelegate| + void GLContextSetDamageRegion(const std::optional& region) override; + + // |GPUSurfaceGLDelegate| + bool GLContextPresent(uint32_t fbo_id, + const std::optional& damage) override; + + // |GPUSurfaceGLDelegate| + intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + + // |GPUSurfaceGLDelegate| + sk_sp GetGLInterface() const override; + + private: + std::unique_ptr display_; + std::unique_ptr onscreen_config_; + std::unique_ptr offscreen_config_; + std::unique_ptr onscreen_surface_; + std::unique_ptr offscreen_surface_; + std::unique_ptr onscreen_context_; + std::unique_ptr offscreen_context_; + std::shared_ptr impeller_context_; + fml::RefPtr native_window_; + + bool is_valid_ = false; + + bool OnGLContextMakeCurrent(); + + bool RecreateOnscreenSurfaceAndMakeOnscreenContextCurrent(); + + FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceGLImpeller); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_IMPELLER_H_ diff --git a/engine/src/flutter/shell/platform/android/android_surface_gl.cc b/engine/src/flutter/shell/platform/android/android_surface_gl_skia.cc similarity index 77% rename from engine/src/flutter/shell/platform/android/android_surface_gl.cc rename to engine/src/flutter/shell/platform/android/android_surface_gl_skia.cc index 51e72f494fb..d1b1b145b1b 100644 --- a/engine/src/flutter/shell/platform/android/android_surface_gl.cc +++ b/engine/src/flutter/shell/platform/android/android_surface_gl_skia.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/android/android_surface_gl.h" +#include "flutter/shell/platform/android/android_surface_gl_skia.h" #include #include #include "flutter/fml/logging.h" #include "flutter/fml/memory/ref_ptr.h" +#include "flutter/shell/platform/android/android_egl_surface.h" #include "flutter/shell/platform/android/android_shell_holder.h" namespace flutter { @@ -19,7 +20,7 @@ constexpr char kEmulatorRendererPrefix[] = "Android Emulator OpenGL ES Translator"; } // anonymous namespace -AndroidSurfaceGL::AndroidSurfaceGL( +AndroidSurfaceGLSkia::AndroidSurfaceGLSkia( const std::shared_ptr& android_context, std::shared_ptr jni_facade) : AndroidSurface(android_context), @@ -33,9 +34,9 @@ AndroidSurfaceGL::AndroidSurfaceGL( } } -AndroidSurfaceGL::~AndroidSurfaceGL() = default; +AndroidSurfaceGLSkia::~AndroidSurfaceGLSkia() = default; -void AndroidSurfaceGL::TeardownOnScreenContext() { +void AndroidSurfaceGLSkia::TeardownOnScreenContext() { // When the onscreen surface is destroyed, the context and the surface // instance should be deleted. Issue: // https://github.com/flutter/flutter/issues/64414 @@ -43,26 +44,27 @@ void AndroidSurfaceGL::TeardownOnScreenContext() { onscreen_surface_ = nullptr; } -bool AndroidSurfaceGL::IsValid() const { +bool AndroidSurfaceGLSkia::IsValid() const { return offscreen_surface_ && GLContextPtr()->IsValid(); } -std::unique_ptr AndroidSurfaceGL::CreateGPUSurface( +std::unique_ptr AndroidSurfaceGLSkia::CreateGPUSurface( GrDirectContext* gr_context) { if (gr_context) { - return std::make_unique(sk_ref_sp(gr_context), this, true); + return std::make_unique(sk_ref_sp(gr_context), this, + true); } else { sk_sp main_skia_context = GLContextPtr()->GetMainSkiaContext(); if (!main_skia_context) { - main_skia_context = GPUSurfaceGL::MakeGLContext(this); + main_skia_context = GPUSurfaceGLSkia::MakeGLContext(this); GLContextPtr()->SetMainSkiaContext(main_skia_context); } - return std::make_unique(main_skia_context, this, true); + return std::make_unique(main_skia_context, this, true); } } -bool AndroidSurfaceGL::OnScreenSurfaceResize(const SkISize& size) { +bool AndroidSurfaceGLSkia::OnScreenSurfaceResize(const SkISize& size) { FML_DCHECK(IsValid()); FML_DCHECK(onscreen_surface_); FML_DCHECK(native_window_); @@ -85,20 +87,20 @@ bool AndroidSurfaceGL::OnScreenSurfaceResize(const SkISize& size) { return true; } -bool AndroidSurfaceGL::ResourceContextMakeCurrent() { +bool AndroidSurfaceGLSkia::ResourceContextMakeCurrent() { FML_DCHECK(IsValid()); auto status = offscreen_surface_->MakeCurrent(); return status != AndroidEGLSurfaceMakeCurrentStatus::kFailure; } -bool AndroidSurfaceGL::ResourceContextClearCurrent() { +bool AndroidSurfaceGLSkia::ResourceContextClearCurrent() { FML_DCHECK(IsValid()); EGLBoolean result = eglMakeCurrent(eglGetCurrentDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return result == EGL_TRUE; } -bool AndroidSurfaceGL::SetNativeWindow( +bool AndroidSurfaceGLSkia::SetNativeWindow( fml::RefPtr window) { FML_DCHECK(IsValid()); FML_DCHECK(window); @@ -114,7 +116,7 @@ bool AndroidSurfaceGL::SetNativeWindow( return true; } -std::unique_ptr AndroidSurfaceGL::GLContextMakeCurrent() { +std::unique_ptr AndroidSurfaceGLSkia::GLContextMakeCurrent() { FML_DCHECK(IsValid()); FML_DCHECK(onscreen_surface_); auto status = onscreen_surface_->MakeCurrent(); @@ -123,12 +125,12 @@ std::unique_ptr AndroidSurfaceGL::GLContextMakeCurrent() { return std::move(default_context_result); } -bool AndroidSurfaceGL::GLContextClearCurrent() { +bool AndroidSurfaceGLSkia::GLContextClearCurrent() { FML_DCHECK(IsValid()); return GLContextPtr()->ClearCurrent(); } -SurfaceFrame::FramebufferInfo AndroidSurfaceGL::GLContextFramebufferInfo() +SurfaceFrame::FramebufferInfo AndroidSurfaceGLSkia::GLContextFramebufferInfo() const { FML_DCHECK(IsValid()); SurfaceFrame::FramebufferInfo res; @@ -145,27 +147,28 @@ SurfaceFrame::FramebufferInfo AndroidSurfaceGL::GLContextFramebufferInfo() return res; } -void AndroidSurfaceGL::GLContextSetDamageRegion( +void AndroidSurfaceGLSkia::GLContextSetDamageRegion( const std::optional& region) { FML_DCHECK(IsValid()); onscreen_surface_->SetDamageRegion(region); } -bool AndroidSurfaceGL::GLContextPresent(uint32_t fbo_id, - const std::optional& damage) { +bool AndroidSurfaceGLSkia::GLContextPresent( + uint32_t fbo_id, + const std::optional& damage) { FML_DCHECK(IsValid()); FML_DCHECK(onscreen_surface_); return onscreen_surface_->SwapBuffers(damage); } -intptr_t AndroidSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { +intptr_t AndroidSurfaceGLSkia::GLContextFBO(GLFrameInfo frame_info) const { FML_DCHECK(IsValid()); // The default window bound framebuffer on Android. return 0; } // |GPUSurfaceGLDelegate| -sk_sp AndroidSurfaceGL::GetGLInterface() const { +sk_sp AndroidSurfaceGLSkia::GetGLInterface() const { // This is a workaround for a bug in the Android emulator EGL/GLES // implementation. Some versions of the emulator will not update the // GL version string when the process switches to a new EGL context @@ -197,22 +200,22 @@ sk_sp AndroidSurfaceGL::GetGLInterface() const { return GPUSurfaceGLDelegate::GetGLInterface(); } -AndroidContextGL* AndroidSurfaceGL::GLContextPtr() const { - return reinterpret_cast(android_context_.get()); +AndroidContextGLSkia* AndroidSurfaceGLSkia::GLContextPtr() const { + return reinterpret_cast(android_context_.get()); } -std::unique_ptr AndroidSurfaceGL::CreateSnapshotSurface() { +std::unique_ptr AndroidSurfaceGLSkia::CreateSnapshotSurface() { if (!onscreen_surface_ || !onscreen_surface_->IsValid()) { onscreen_surface_ = GLContextPtr()->CreatePbufferSurface(); } sk_sp main_skia_context = GLContextPtr()->GetMainSkiaContext(); if (!main_skia_context) { - main_skia_context = GPUSurfaceGL::MakeGLContext(this); + main_skia_context = GPUSurfaceGLSkia::MakeGLContext(this); GLContextPtr()->SetMainSkiaContext(main_skia_context); } - return std::make_unique(main_skia_context, this, true); + return std::make_unique(main_skia_context, this, true); } } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/android_surface_gl.h b/engine/src/flutter/shell/platform/android/android_surface_gl_skia.h similarity index 77% rename from engine/src/flutter/shell/platform/android/android_surface_gl.h rename to engine/src/flutter/shell/platform/android/android_surface_gl_skia.h index 92ddd6361a9..4d7705590c8 100644 --- a/engine/src/flutter/shell/platform/android/android_surface_gl.h +++ b/engine/src/flutter/shell/platform/android/android_surface_gl_skia.h @@ -2,29 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_H_ +#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_SKIA_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_SKIA_H_ #include #include #include "flutter/fml/macros.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" -#include "flutter/shell/platform/android/android_context_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" +#include "flutter/shell/platform/android/android_context_gl_skia.h" #include "flutter/shell/platform/android/android_environment_gl.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/shell/platform/android/surface/android_surface.h" namespace flutter { -class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, - public AndroidSurface { +class AndroidSurfaceGLSkia final : public GPUSurfaceGLDelegate, + public AndroidSurface { public: - AndroidSurfaceGL(const std::shared_ptr& android_context, - std::shared_ptr jni_facade); + AndroidSurfaceGLSkia(const std::shared_ptr& android_context, + std::shared_ptr jni_facade); - ~AndroidSurfaceGL() override; + ~AndroidSurfaceGLSkia() override; // |AndroidSurface| bool IsValid() const override; @@ -90,11 +90,11 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, /// @brief Takes the super class AndroidSurface's AndroidContext and /// return a raw pointer to an AndroidContextGL. /// - AndroidContextGL* GLContextPtr() const; + AndroidContextGLSkia* GLContextPtr() const; - FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceGL); + FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceGLSkia); }; } // namespace flutter -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_H_ +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_SKIA_H_ diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java index a9b9a382a74..83c522421ce 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java @@ -42,6 +42,8 @@ public class FlutterShellArgs { public static final String ARG_TRACE_SKIA_ALLOWLIST = "--trace-skia-allowlist="; public static final String ARG_KEY_TRACE_SYSTRACE = "trace-systrace"; public static final String ARG_TRACE_SYSTRACE = "--trace-systrace"; + public static final String ARG_KEY_ENABLE_IMPELLER = "enable-impeller"; + public static final String ARG_ENABLE_IMPELLER = "--enable-impeller"; public static final String ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION = "dump-skp-on-shader-compilation"; public static final String ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION = @@ -106,6 +108,9 @@ public class FlutterShellArgs { if (intent.getBooleanExtra(ARG_KEY_TRACE_SYSTRACE, false)) { args.add(ARG_TRACE_SYSTRACE); } + if (intent.getBooleanExtra(ARG_KEY_ENABLE_IMPELLER, false)) { + args.add(ARG_ENABLE_IMPELLER); + } if (intent.getBooleanExtra(ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION, false)) { args.add(ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION); } diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.cc b/engine/src/flutter/shell/platform/android/platform_view_android.cc index a41018c9146..6d6068ac715 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android.cc @@ -10,9 +10,11 @@ #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/common/shell_io_manager.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" -#include "flutter/shell/platform/android/android_context_gl.h" +#include "flutter/shell/platform/android/android_context_gl_impeller.h" +#include "flutter/shell/platform/android/android_context_gl_skia.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" -#include "flutter/shell/platform/android/android_surface_gl.h" +#include "flutter/shell/platform/android/android_surface_gl_impeller.h" +#include "flutter/shell/platform/android/android_surface_gl_skia.h" #include "flutter/shell/platform/android/android_surface_software.h" #include "flutter/shell/platform/android/context/android_context.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" @@ -26,8 +28,11 @@ namespace flutter { AndroidSurfaceFactoryImpl::AndroidSurfaceFactoryImpl( const std::shared_ptr& context, - std::shared_ptr jni_facade) - : android_context_(context), jni_facade_(jni_facade) {} + std::shared_ptr jni_facade, + bool enable_impeller) + : android_context_(context), + jni_facade_(jni_facade), + enable_impeller_(enable_impeller) {} AndroidSurfaceFactoryImpl::~AndroidSurfaceFactoryImpl() = default; @@ -37,7 +42,13 @@ std::unique_ptr AndroidSurfaceFactoryImpl::CreateSurface() { return std::make_unique(android_context_, jni_facade_); case AndroidRenderingAPI::kOpenGLES: - return std::make_unique(android_context_, jni_facade_); + if (enable_impeller_) { + return std::make_unique(android_context_, + jni_facade_); + } else { + return std::make_unique(android_context_, + jni_facade_); + } default: FML_DCHECK(false); return nullptr; @@ -47,13 +58,20 @@ std::unique_ptr AndroidSurfaceFactoryImpl::CreateSurface() { static std::shared_ptr CreateAndroidContext( bool use_software_rendering, const flutter::TaskRunners task_runners, - uint8_t msaa_samples) { + uint8_t msaa_samples, + bool enable_impeller) { if (use_software_rendering) { return std::make_shared(AndroidRenderingAPI::kSoftware); } - return std::make_unique( - AndroidRenderingAPI::kOpenGLES, - fml::MakeRefCounted(), task_runners, msaa_samples); + if (enable_impeller) { + return std::make_unique(); + } + return std::make_unique( + AndroidRenderingAPI::kOpenGLES, // + fml::MakeRefCounted(), // + task_runners, // + msaa_samples // + ); } PlatformViewAndroid::PlatformViewAndroid( @@ -62,12 +80,15 @@ PlatformViewAndroid::PlatformViewAndroid( std::shared_ptr jni_facade, bool use_software_rendering, uint8_t msaa_samples) - : PlatformViewAndroid(delegate, - std::move(task_runners), - std::move(jni_facade), - CreateAndroidContext(use_software_rendering, - task_runners, - msaa_samples)) {} + : PlatformViewAndroid( + delegate, + std::move(task_runners), + std::move(jni_facade), + CreateAndroidContext( + use_software_rendering, + task_runners, + msaa_samples, + delegate.OnPlatformViewGetSettings().enable_impeller)) {} PlatformViewAndroid::PlatformViewAndroid( PlatformView::Delegate& delegate, @@ -83,7 +104,8 @@ PlatformViewAndroid::PlatformViewAndroid( FML_CHECK(android_context_->IsValid()) << "Could not create surface from invalid Android context."; surface_factory_ = std::make_shared( - android_context_, jni_facade_); + android_context_, jni_facade_, + delegate.OnPlatformViewGetSettings().enable_impeller); android_surface_ = surface_factory_->CreateSurface(); FML_CHECK(android_surface_ && android_surface_->IsValid()) diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.h b/engine/src/flutter/shell/platform/android/platform_view_android.h index 1226af1681f..073676cc137 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.h +++ b/engine/src/flutter/shell/platform/android/platform_view_android.h @@ -27,7 +27,8 @@ namespace flutter { class AndroidSurfaceFactoryImpl : public AndroidSurfaceFactory { public: AndroidSurfaceFactoryImpl(const std::shared_ptr& context, - std::shared_ptr jni_facade); + std::shared_ptr jni_facade, + bool enable_impeller); ~AndroidSurfaceFactoryImpl() override; @@ -36,6 +37,7 @@ class AndroidSurfaceFactoryImpl : public AndroidSurfaceFactory { private: const std::shared_ptr& android_context_; std::shared_ptr jni_facade_; + const bool enable_impeller_; }; class PlatformViewAndroid final : public PlatformView { diff --git a/engine/src/flutter/shell/platform/android/surface/android_surface_mock.h b/engine/src/flutter/shell/platform/android/surface/android_surface_mock.h index 04a6b2e03f1..946358c5e93 100644 --- a/engine/src/flutter/shell/platform/android/surface/android_surface_mock.h +++ b/engine/src/flutter/shell/platform/android/surface/android_surface_mock.h @@ -5,7 +5,7 @@ #ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_MOCK_H_ #define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_MOCK_H_ -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #include "flutter/shell/platform/android/surface/android_surface.h" #include "gmock/gmock.h" diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm index eb3cc915480..d183a29150f 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm @@ -7,8 +7,8 @@ #import #include "flutter/shell/common/shell_io_manager.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #import "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" namespace flutter { diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.h b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.h index 3ea6fc40739..f8ba3806798 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.h +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.h @@ -7,7 +7,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #import "flutter/shell/platform/darwin/ios/ios_context.h" #import "flutter/shell/platform/darwin/ios/ios_render_target_gl.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.mm index fb1658e2bbe..a51c724a8e2 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_gl.mm @@ -5,7 +5,7 @@ #import "flutter/shell/platform/darwin/ios/ios_surface_gl.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #import "flutter/shell/platform/darwin/ios/ios_context_gl.h" namespace flutter { @@ -37,16 +37,16 @@ void IOSSurfaceGL::UpdateStorageSizeIfNecessary() { // |IOSSurface| std::unique_ptr IOSSurfaceGL::CreateGPUSurface(GrDirectContext* gr_context) { if (gr_context) { - return std::make_unique(sk_ref_sp(gr_context), this, true); + return std::make_unique(sk_ref_sp(gr_context), this, true); } else { IOSContextGL* gl_context = CastToGLContext(GetContext()); sk_sp context = gl_context->GetMainContext(); if (!context) { - context = GPUSurfaceGL::MakeGLContext(this); + context = GPUSurfaceGLSkia::MakeGLContext(this); gl_context->SetMainContext(context); } - return std::make_unique(context, this, true); + return std::make_unique(context, this, true); } } diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.cc index dfe67e290b0..0a59dcdc78f 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.cc @@ -79,8 +79,9 @@ EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const { // |EmbedderSurface| std::unique_ptr EmbedderSurfaceGL::CreateGPUSurface() { const bool render_to_surface = !external_view_embedder_; - return std::make_unique(this, // GPU surface GL delegate - render_to_surface // render to surface + return std::make_unique( + this, // GPU surface GL delegate + render_to_surface // render to surface ); } diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.h b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.h index 16700702810..8cec798afe4 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl.h @@ -6,7 +6,7 @@ #define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_GL_H_ #include "flutter/fml/macros.h" -#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/gpu/gpu_surface_gl_skia.h" #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" #include "flutter/shell/platform/embedder/embedder_surface.h"