From c45b5c0dee81868ac00a59af93f387189959cd83 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 12 Jun 2019 12:32:09 -0700 Subject: [PATCH] Wire up Swiftshader based OpenGL ES unit-tests on hosts. (flutter/engine#9264) Currently, all our host unit-tests that have rendering concerns use the software backend because of OpenGL ES availability and stability issues on the various platforms where we run host tests. Unfortunately, entire subsystems are disabled (and not tested) when rendering with the software backend. This patch pulls in SwiftShader and via pending patches in the buildroot, configures the host unit-tests to optionally use OpenGL ES in a stable manner without relying on the OpenGL drivers being present (and functional). I have wired up the embedder test fixture in this patch to use the SwiftShader based OpenGL ES driver. I will update the shell and runtime unittests in a subsequent patch as well. The on and offscreen surfaces are configured as 1x1 pbuffer surface because we should be able to write pixel tests using OpenGL directly wihout having to deal with surfaces. --- DEPS | 6 +- .../flutter/ci/licenses_golden/tool_signature | 2 +- .../flutter/shell/platform/embedder/BUILD.gn | 54 +++-- .../shell/platform/embedder/embedder.cc | 1 + .../embedder/tests/embedder_config_builder.cc | 31 ++- .../embedder/tests/embedder_config_builder.h | 3 + .../embedder/tests/embedder_context.cc | 34 +++ .../embedder/tests/embedder_context.h | 16 ++ .../tests/embedder_test_gl_surface.cc | 228 ++++++++++++++++++ .../embedder/tests/embedder_test_gl_surface.h | 51 ++++ .../embedder/tests/embedder_unittests.cc | 7 + engine/src/flutter/tools/gn | 6 + .../src/flutter/tools/licenses/lib/main.dart | 1 + 13 files changed, 414 insertions(+), 26 deletions(-) create mode 100644 engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.cc create mode 100644 engine/src/flutter/shell/platform/embedder/tests/embedder_test_gl_surface.h 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); }