未验证 提交 7bb5b9ae 编写于 作者: C Chinmay Garde 提交者: GitHub

Wire up Swiftshader based OpenGL ES unit-tests on hosts. (#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.
上级 67aadb62
......@@ -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',
......
Signature: 5b10e36374c7d600de6c632fde955f7d
Signature: 499a560047281c7ce35f227b57030b8b
......@@ -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") {
......
......@@ -340,6 +340,7 @@ FlutterEngineResult FlutterEngineRun(size_t version,
}
if (!IsRendererValid(config)) {
FML_LOG(WARNING) << "Invalid renderer config.";
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}
......
......@@ -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<EmbedderContext*>(context)->GLMakeCurrent();
};
opengl_renderer_config_.clear_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderContext*>(context)->GLClearCurrent();
};
opengl_renderer_config_.present = [](void* context) -> bool {
return reinterpret_cast<EmbedderContext*>(context)->GLPresent();
};
opengl_renderer_config_.fbo_callback = [](void* context) -> uint32_t {
return reinterpret_cast<EmbedderContext*>(context)->GLGetFramebuffer();
};
opengl_renderer_config_.make_resource_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderContext*>(context)->GLMakeResourceCurrent();
};
opengl_renderer_config_.gl_proc_resolver = [](void* context,
const char* name) -> void* {
return reinterpret_cast<EmbedderContext*>(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();
}
......
......@@ -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<std::string> command_line_arguments_;
......
......@@ -111,5 +111,39 @@ EmbedderContext::GetUpdateSemanticsCustomActionCallbackHook() {
};
}
void EmbedderContext::SetupOpenGLSurface() {
gl_surface_ = std::make_unique<EmbedderTestGLSurface>();
}
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
......@@ -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<TestDartNativeResolver> native_resolver_;
SemanticsNodeCallback update_semantics_node_callback_;
SemanticsActionCallback update_semantics_custom_action_callback_;
std::unique_ptr<EmbedderTestGLSurface> 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);
};
......
// 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 <EGL/egl.h>
#include <sstream>
#include <string>
#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<void*>(symbol);
}
} // namespace flutter
// 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_
......@@ -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
......@@ -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
......
......@@ -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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册