diff --git a/DEPS b/DEPS index 673773eaee8..7128c980a08 100644 --- a/DEPS +++ b/DEPS @@ -19,6 +19,7 @@ vars = { 'chromium_git': 'https://chromium.googlesource.com', + 'swiftshader_git': 'https://swiftshader.googlesource.com', 'dart_git': 'https://dart.googlesource.com', 'fuchsia_git': 'https://fuchsia.googlesource.com', 'github_git': 'https://github.com', @@ -121,7 +122,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '263ee3b119f686591f8bb131bf22f53d384c2be2', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '95662021f20c859d1a1d30d3e436375b1078a39d', # Fuchsia compatibility # @@ -394,6 +395,9 @@ deps = { 'src/third_party/vulkan': Var('github_git') + '/KhronosGroup/Vulkan-Docs.git' + '@' + 'v1.1.91', + 'src/third_party/swiftshader': + Var('swiftshader_git') + '/SwiftShader.git' + '@' + '95b1db9619fb0f5f232c09995bc00729273f74ee', + 'src/third_party/pkg/when': Var('dart_git') + '/when.git' + '@' + '0.2.0', diff --git a/engine/src/flutter/ci/licenses_golden/tool_signature b/engine/src/flutter/ci/licenses_golden/tool_signature index bd4e546b731..6f6bc887e14 100644 --- a/engine/src/flutter/ci/licenses_golden/tool_signature +++ b/engine/src/flutter/ci/licenses_golden/tool_signature @@ -1,2 +1,2 @@ -Signature: 5b10e36374c7d600de6c632fde955f7d +Signature: 499a560047281c7ce35f227b57030b8b diff --git a/engine/src/flutter/shell/platform/embedder/BUILD.gn b/engine/src/flutter/shell/platform/embedder/BUILD.gn index cc60500a1a3..a068a2b18f6 100644 --- a/engine/src/flutter/shell/platform/embedder/BUILD.gn +++ b/engine/src/flutter/shell/platform/embedder/BUILD.gn @@ -60,33 +60,41 @@ test_fixtures("fixtures") { dart_main = "fixtures/main.dart" } -executable("embedder_unittests") { - testonly = true +if (is_mac || is_linux || is_win) { + executable("embedder_unittests") { + testonly = true - configs += [ "$flutter_root:export_dynamic_symbols" ] + configs += [ + "$flutter_root:export_dynamic_symbols", + "//third_party/swiftshader_flutter:swiftshader_config", + ] - include_dirs = [ "." ] + include_dirs = [ "." ] - sources = [ - "tests/embedder_a11y_unittests.cc", - "tests/embedder_config_builder.cc", - "tests/embedder_config_builder.h", - "tests/embedder_context.cc", - "tests/embedder_context.h", - "tests/embedder_test.cc", - "tests/embedder_test.h", - "tests/embedder_unittests.cc", - ] + sources = [ + "tests/embedder_a11y_unittests.cc", + "tests/embedder_config_builder.cc", + "tests/embedder_config_builder.h", + "tests/embedder_context.cc", + "tests/embedder_context.h", + "tests/embedder_test.cc", + "tests/embedder_test.h", + "tests/embedder_test_gl_surface.cc", + "tests/embedder_test_gl_surface.h", + "tests/embedder_unittests.cc", + ] - deps = [ - ":embedder", - ":fixtures", - "$flutter_root/lib/ui", - "$flutter_root/runtime", - "$flutter_root/testing:dart", - "//third_party/skia", - "//third_party/tonic", - ] + deps = [ + ":embedder", + ":fixtures", + "$flutter_root/lib/ui", + "$flutter_root/runtime", + "$flutter_root/testing:dart", + "//third_party/skia", + "//third_party/swiftshader_flutter:swiftshader", + "//third_party/tonic", + ] + } } shared_library("flutter_engine_library") { diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index e49c08e1972..977cf4250d3 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -340,6 +340,7 @@ FlutterEngineResult FlutterEngineRun(size_t version, } if (!IsRendererValid(config)) { + FML_LOG(WARNING) << "Invalid renderer config."; return LOG_EMBEDDER_ERROR(kInvalidArguments); } diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.cc index d1726503576..9021eaee1f9 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.cc @@ -12,8 +12,31 @@ EmbedderConfigBuilder::EmbedderConfigBuilder( InitializationPreference preference) : context_(context) { project_args_.struct_size = sizeof(project_args_); - software_renderer_config_.struct_size = sizeof(FlutterSoftwareRendererConfig); + custom_task_runners_.struct_size = sizeof(FlutterCustomTaskRunners); + + opengl_renderer_config_.struct_size = sizeof(FlutterOpenGLRendererConfig); + opengl_renderer_config_.make_current = [](void* context) -> bool { + return reinterpret_cast(context)->GLMakeCurrent(); + }; + opengl_renderer_config_.clear_current = [](void* context) -> bool { + return reinterpret_cast(context)->GLClearCurrent(); + }; + opengl_renderer_config_.present = [](void* context) -> bool { + return reinterpret_cast(context)->GLPresent(); + }; + opengl_renderer_config_.fbo_callback = [](void* context) -> uint32_t { + return reinterpret_cast(context)->GLGetFramebuffer(); + }; + opengl_renderer_config_.make_resource_current = [](void* context) -> bool { + return reinterpret_cast(context)->GLMakeResourceCurrent(); + }; + opengl_renderer_config_.gl_proc_resolver = [](void* context, + const char* name) -> void* { + return reinterpret_cast(context)->GLGetProcAddress(name); + }; + + software_renderer_config_.struct_size = sizeof(FlutterSoftwareRendererConfig); software_renderer_config_.surface_present_callback = [](void*, const void*, size_t, size_t) { return true; }; @@ -33,6 +56,12 @@ void EmbedderConfigBuilder::SetSoftwareRendererConfig() { renderer_config_.software = software_renderer_config_; } +void EmbedderConfigBuilder::SetOpenGLRendererConfig() { + renderer_config_.type = FlutterRendererType::kOpenGL; + renderer_config_.open_gl = opengl_renderer_config_; + context_.SetupOpenGLSurface(); +} + void EmbedderConfigBuilder::SetAssetsPath() { project_args_.assets_path = context_.GetAssetsPath().c_str(); } diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.h b/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.h index b416278f1a3..1c05f835cc3 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.h +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_config_builder.h @@ -42,6 +42,8 @@ class EmbedderConfigBuilder { void SetSoftwareRendererConfig(); + void SetOpenGLRendererConfig(); + void SetAssetsPath(); void SetSnapshots(); @@ -63,6 +65,7 @@ class EmbedderConfigBuilder { FlutterProjectArgs project_args_ = {}; FlutterRendererConfig renderer_config_ = {}; FlutterSoftwareRendererConfig software_renderer_config_ = {}; + FlutterOpenGLRendererConfig opengl_renderer_config_ = {}; std::string dart_entrypoint_; FlutterCustomTaskRunners custom_task_runners_ = {}; std::vector command_line_arguments_; diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_context.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_context.cc index 46b8c2e6f14..bf066ff1079 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_context.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_context.cc @@ -111,5 +111,39 @@ EmbedderContext::GetUpdateSemanticsCustomActionCallbackHook() { }; } +void EmbedderContext::SetupOpenGLSurface() { + gl_surface_ = std::make_unique(); +} + +bool EmbedderContext::GLMakeCurrent() { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->MakeCurrent(); +} + +bool EmbedderContext::GLClearCurrent() { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->ClearCurrent(); +} + +bool EmbedderContext::GLPresent() { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->Present(); +} + +uint32_t EmbedderContext::GLGetFramebuffer() { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->GetFramebuffer(); +} + +bool EmbedderContext::GLMakeResourceCurrent() { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->MakeResourceCurrent(); +} + +void* EmbedderContext::GLGetProcAddress(const char* name) { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + return gl_surface_->GetProcAddress(name); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_context.h b/engine/src/flutter/shell/platform/embedder/tests/embedder_context.h index 5c166063b4c..c2d6d3c7528 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_context.h +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_context.h @@ -14,6 +14,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/tests/embedder_test_gl_surface.h" #include "flutter/testing/test_dart_native_resolver.h" namespace flutter { @@ -61,6 +62,7 @@ class EmbedderContext { std::shared_ptr native_resolver_; SemanticsNodeCallback update_semantics_node_callback_; SemanticsActionCallback update_semantics_custom_action_callback_; + std::unique_ptr gl_surface_; // lazy static VoidCallback GetIsolateCreateCallbackHook(); @@ -74,6 +76,20 @@ class EmbedderContext { void SetNativeResolver(); + void SetupOpenGLSurface(); + + bool GLMakeCurrent(); + + bool GLClearCurrent(); + + bool GLPresent(); + + uint32_t GLGetFramebuffer(); + + bool GLMakeResourceCurrent(); + + void* GLGetProcAddress(const char* name); + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderContext); }; diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.cc new file mode 100644 index 00000000000..54c2d6e6ff9 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.cc @@ -0,0 +1,228 @@ +// 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/embedder/tests/embedder_test_gl_surface.h" + +#include + +#include +#include + +#include "flutter/fml/logging.h" + +namespace flutter { + +static std::string GetEGLError() { + std::stringstream stream; + + auto error = ::eglGetError(); + + stream << "EGL Result: '"; + + switch (error) { + case EGL_SUCCESS: + stream << "EGL_SUCCESS"; + break; + case EGL_NOT_INITIALIZED: + stream << "EGL_NOT_INITIALIZED"; + break; + case EGL_BAD_ACCESS: + stream << "EGL_BAD_ACCESS"; + break; + case EGL_BAD_ALLOC: + stream << "EGL_BAD_ALLOC"; + break; + case EGL_BAD_ATTRIBUTE: + stream << "EGL_BAD_ATTRIBUTE"; + break; + case EGL_BAD_CONTEXT: + stream << "EGL_BAD_CONTEXT"; + break; + case EGL_BAD_CONFIG: + stream << "EGL_BAD_CONFIG"; + break; + case EGL_BAD_CURRENT_SURFACE: + stream << "EGL_BAD_CURRENT_SURFACE"; + break; + case EGL_BAD_DISPLAY: + stream << "EGL_BAD_DISPLAY"; + break; + case EGL_BAD_SURFACE: + stream << "EGL_BAD_SURFACE"; + break; + case EGL_BAD_MATCH: + stream << "EGL_BAD_MATCH"; + break; + case EGL_BAD_PARAMETER: + stream << "EGL_BAD_PARAMETER"; + break; + case EGL_BAD_NATIVE_PIXMAP: + stream << "EGL_BAD_NATIVE_PIXMAP"; + break; + case EGL_BAD_NATIVE_WINDOW: + stream << "EGL_BAD_NATIVE_WINDOW"; + break; + case EGL_CONTEXT_LOST: + stream << "EGL_CONTEXT_LOST"; + break; + default: + stream << "Unknown"; + } + + stream << "' (0x" << std::hex << error << std::dec << ")."; + return stream.str(); +} + +EmbedderTestGLSurface::EmbedderTestGLSurface() { + display_ = ::eglGetDisplay(EGL_DEFAULT_DISPLAY); + FML_CHECK(display_ != EGL_NO_DISPLAY); + + auto result = ::eglInitialize(display_, NULL, NULL); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + + EGLConfig config = {0}; + + EGLint num_config = 0; + const EGLint attribute_list[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_CONFORMANT, + EGL_OPENGL_ES2_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_NONE}; + + result = ::eglChooseConfig(display_, attribute_list, &config, 1, &num_config); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + FML_CHECK(num_config == 1) << GetEGLError(); + + { + const EGLint surface_attributes[] = { + EGL_HEIGHT, 1, // + EGL_WIDTH, 1, // + EGL_NONE, + }; + + onscreen_surface_ = + ::eglCreatePbufferSurface(display_, // display connection + config, // config + surface_attributes // surface attributes + ); + FML_CHECK(onscreen_surface_ != EGL_NO_SURFACE) << GetEGLError(); + + offscreen_surface_ = + ::eglCreatePbufferSurface(display_, // display connection + config, // config + surface_attributes // surface attributes + ); + FML_CHECK(offscreen_surface_ != EGL_NO_SURFACE) << GetEGLError(); + } + + { + const EGLint context_attributes[] = { + EGL_CONTEXT_CLIENT_VERSION, // + 2, // + EGL_NONE // + }; + + onscreen_context_ = + ::eglCreateContext(display_, // display connection + config, // config + EGL_NO_CONTEXT, // sharegroup + context_attributes // context attributes + ); + FML_CHECK(onscreen_context_ != EGL_NO_CONTEXT) << GetEGLError(); + + offscreen_context_ = + ::eglCreateContext(display_, // display connection + config, // config + onscreen_context_, // sharegroup + context_attributes // context attributes + ); + FML_CHECK(offscreen_context_ != EGL_NO_CONTEXT) << GetEGLError(); + } +} + +EmbedderTestGLSurface::~EmbedderTestGLSurface() { + auto result = ::eglDestroyContext(display_, onscreen_context_); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + + result = ::eglDestroyContext(display_, offscreen_context_); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + + result = ::eglDestroySurface(display_, onscreen_surface_); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + + result = ::eglDestroySurface(display_, offscreen_surface_); + FML_CHECK(result == EGL_TRUE) << GetEGLError(); + + result = ::eglTerminate(display_); + FML_CHECK(result == EGL_TRUE); +} + +bool EmbedderTestGLSurface::MakeCurrent() { + auto result = ::eglMakeCurrent(display_, onscreen_surface_, onscreen_surface_, + onscreen_context_); + + if (result == EGL_FALSE) { + FML_LOG(ERROR) << "Could not make the context current. " << GetEGLError(); + } + + return result == EGL_TRUE; +} + +bool EmbedderTestGLSurface::ClearCurrent() { + auto result = ::eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + if (result == EGL_FALSE) { + FML_LOG(ERROR) << "Could not clear the current context. " << GetEGLError(); + } + + return result == EGL_TRUE; +} + +bool EmbedderTestGLSurface::Present() { + auto result = ::eglSwapBuffers(display_, onscreen_surface_); + + if (result == EGL_FALSE) { + FML_LOG(ERROR) << "Could not swap buffers. " << GetEGLError(); + } + + return result == EGL_TRUE; +} + +uint32_t EmbedderTestGLSurface::GetFramebuffer() { + // Return FBO0 + return 0; +} + +bool EmbedderTestGLSurface::MakeResourceCurrent() { + auto result = ::eglMakeCurrent(display_, offscreen_surface_, + offscreen_surface_, offscreen_context_); + + if (result == EGL_FALSE) { + FML_LOG(ERROR) << "Could not make the resource context current. " + << GetEGLError(); + } + + return result == EGL_TRUE; +} + +void* EmbedderTestGLSurface::GetProcAddress(const char* name) { + auto symbol = ::eglGetProcAddress(name); + if (symbol == NULL) { + FML_LOG(ERROR) << "Could not fetch symbol for name: " << name; + } + return reinterpret_cast(symbol); +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.h b/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.h new file mode 100644 index 00000000000..0d7da604310 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.h @@ -0,0 +1,51 @@ +// 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_EMBEDDER_TESTS_EMBEDDER_TEST_GL_SURFACE_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_TEST_GL_SURFACE_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/embedder/embedder.h" + +namespace flutter { + +class EmbedderTestGLSurface { + public: + EmbedderTestGLSurface(); + + ~EmbedderTestGLSurface(); + + bool MakeCurrent(); + + bool ClearCurrent(); + + bool Present(); + + uint32_t GetFramebuffer(); + + bool MakeResourceCurrent(); + + void* GetProcAddress(const char* name); + + private: + // Importing the EGL.h pulls in platform headers which are problematic + // (especially X11 which #defineds types like Bool). Any TUs importing this + // header then become susceptible to failures because of platform specific + // craziness. Don't expose EGL internals via this header. + using EGLDisplay = void*; + using EGLContext = void*; + using EGLSurface = void*; + + EGLDisplay display_; + EGLContext onscreen_context_; + EGLContext offscreen_context_; + EGLSurface onscreen_surface_; + EGLSurface offscreen_surface_; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestGLSurface); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_TEST_GL_SURFACE_H_ diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc index eb915d3d28d..4dcf2d17209 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc @@ -209,5 +209,12 @@ TEST(EmbedderTestNoFixture, CanGetCurrentTimeInNanoseconds) { ASSERT_LT((point2 - point1), fml::TimeDelta::FromMilliseconds(1)); } +TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) { + EmbedderConfigBuilder builder(GetEmbedderContext()); + builder.SetOpenGLRendererConfig(); + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/tools/gn b/engine/src/flutter/tools/gn index 7b53b6f5c47..c0c3262031d 100755 --- a/engine/src/flutter/tools/gn +++ b/engine/src/flutter/tools/gn @@ -98,6 +98,12 @@ def to_gn_args(args): gn_args['android_full_debug'] = args.target_os == 'android' and args.unoptimized gn_args['is_clang'] = not sys.platform.startswith(('cygwin', 'win')) + if args.target_os == 'android' or args.target_os == 'ios': + gn_args['skia_gl_standard'] = 'gles' + else: + # We explicitly don't want to pick GL because we run GLES tests using SwiftShader. + gn_args['skia_gl_standard'] = '' + if not sys.platform.startswith(('cygwin', 'win')): gn_args['use_clang_static_analyzer'] = args.clang_static_analyzer diff --git a/engine/src/flutter/tools/licenses/lib/main.dart b/engine/src/flutter/tools/licenses/lib/main.dart index 62662313bf3..14d36247235 100644 --- a/engine/src/flutter/tools/licenses/lib/main.dart +++ b/engine/src/flutter/tools/licenses/lib/main.dart @@ -1753,6 +1753,7 @@ class _RepositoryRootThirdPartyDirectory extends _RepositoryGenericThirdPartyDir && entry.name != 'googletest' // only used by tests && entry.name != 'skia' // treated as a separate component && entry.name != 'fontconfig' // not used in standard configurations + && entry.name != 'swiftshader' // only used on hosts for tests && super.shouldRecurse(entry); }