5#define FML_USED_ON_EMBEDDER
10#include <EGL/eglext.h>
11#include <EGL/eglplatform.h>
25#include "impeller/entity/gles/entity_shaders_gles.h"
26#include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
27#include "impeller/entity/gles/modern_shaders_gles.h"
30#include "third_party/abseil-cpp/absl/status/statusor.h"
36class TesterGLContext :
public SwitchableGLContext {
38 TesterGLContext(EGLDisplay display, EGLSurface
surface, EGLContext context)
41 bool SetCurrent()
override {
45 bool RemoveCurrent()
override {
46 ::eglMakeCurrent(
display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
56class TesterGLESDelegate :
public GPUSurfaceGLDelegate {
58 static absl::StatusOr<TesterGLESDelegate> Create() {
60 if (display == EGL_NO_DISPLAY) {
61 return absl::InternalError(
"Could not create EGL display.");
64 if (::eglInitialize(display,
nullptr,
nullptr) != EGL_TRUE) {
65 return absl::InternalError(
"Could not initialize EGL display.");
68 EGLint num_config = 0;
69 const EGLint attribute_list[] = {EGL_RED_SIZE,
89 EGLConfig config =
nullptr;
90 if (::eglChooseConfig(display, attribute_list, &config, 1, &num_config) !=
93 return absl::InternalError(
"Could not choose EGL config.");
96 const EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
100 ::eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
101 if (context == EGL_NO_CONTEXT) {
102 return absl::InternalError(
"Could not create EGL context.");
106 const EGLint surface_attributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
108 ::eglCreatePbufferSurface(display, config, surface_attributes);
109 if (
surface == EGL_NO_SURFACE) {
110 ::eglDestroyContext(display, context);
111 return absl::InternalError(
"Could not create EGL pbuffer surface.");
114 return TesterGLESDelegate(display, context,
surface);
117 TesterGLESDelegate(TesterGLESDelegate&& other)
119 context_(other.context_),
121 other.display_ = EGL_NO_DISPLAY;
122 other.context_ = EGL_NO_CONTEXT;
123 other.surface_ = EGL_NO_SURFACE;
126 virtual ~TesterGLESDelegate() {
131 if (context_ != EGL_NO_CONTEXT) {
132 ::eglDestroyContext(
display_, context_);
138 bool IsContextCurrent()
const { return ::eglGetCurrentContext() == context_; }
141 std::unique_ptr<GLContextResult> GLContextMakeCurrent()
override {
142 if (IsContextCurrent()) {
143 return std::make_unique<GLContextDefaultResult>(
true);
149 return std::make_unique<GLContextSwitch>(
154 bool GLContextClearCurrent()
override {
155 return ::eglMakeCurrent(
display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
156 EGL_NO_CONTEXT) == EGL_TRUE;
160 bool GLContextPresent(
const GLPresentInfo& present_info)
override {
165 GLFBOInfo GLContextFBO(GLFrameInfo frame_info)
const override {
166 return GLFBOInfo{0, std::nullopt};
170 SurfaceFrame::FramebufferInfo GLContextFramebufferInfo()
const override {
171 return SurfaceFrame::FramebufferInfo{.supports_readback =
true};
175 TesterGLESDelegate(EGLDisplay display, EGLContext context, EGLSurface
surface)
178 EGLDisplay
display_ = EGL_NO_DISPLAY;
179 EGLContext context_ = EGL_NO_CONTEXT;
180 EGLSurface
surface_ = EGL_NO_SURFACE;
187 explicit TesterGLESWorker(TesterGLESDelegate* delegate)
190 bool CanReactorReactOnCurrentThreadNow(
195 std::unique_ptr<GLContextResult> result =
delegate_->GLContextMakeCurrent();
196 if (!result->GetResult()) {
202 reinterpret_cast<intptr_t
>(
this),
205 reinterpret_cast<intptr_t
>(
this));
214class TesterContextGLES :
public TesterContext {
216 TesterContextGLES() =
default;
218 ~TesterContextGLES()
override {
220 std::shared_ptr<impeller::Context> raw_context = context_;
221 raw_context->Shutdown();
226 auto delegate_status = TesterGLESDelegate::Create();
227 if (!delegate_status.ok()) {
228 FML_LOG(ERROR) << delegate_status.status().message();
231 delegate_ = std::make_unique<TesterGLESDelegate>(
232 std::move(delegate_status.value()));
234 auto switch_result =
delegate_->GLContextMakeCurrent();
235 if (!switch_result->GetResult()) {
236 FML_LOG(ERROR) <<
"Could not make GLES context current.";
240 auto resolver = [](
const char*
name) ->
void* {
241 return reinterpret_cast<void*
>(eglGetProcAddress(
name));
244 auto gl = std::make_unique<impeller::ProcTableGLES>(resolver);
245 if (!gl->IsValid()) {
246 FML_LOG(ERROR) <<
"Could not create valid proc table.";
250 std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
251 std::make_shared<fml::NonOwnedMapping>(
252 impeller_entity_shaders_gles_data,
253 impeller_entity_shaders_gles_length),
254 std::make_shared<fml::NonOwnedMapping>(
255 impeller_modern_shaders_gles_data,
256 impeller_modern_shaders_gles_length),
257 std::make_shared<fml::NonOwnedMapping>(
258 impeller_framebuffer_blend_shaders_gles_data,
259 impeller_framebuffer_blend_shaders_gles_length),
262 shader_mappings,
false);
265 !
static_cast<std::shared_ptr<impeller::Context>
>(context_)->IsValid()) {
266 FML_LOG(ERROR) <<
"Could not create OpenGLES context.";
270 worker_ = std::make_shared<TesterGLESWorker>(
delegate_.get());
271 context_->AddReactorWorker(worker_);
277 std::shared_ptr<impeller::Context> GetImpellerContext()
const override {
282 std::unique_ptr<Surface> CreateRenderingSurface()
override {
283 auto surface = std::make_unique<GPUSurfaceGLImpeller>(
292 std::unique_ptr<TesterGLESDelegate>
delegate_;
293 std::shared_ptr<TesterGLESWorker> worker_;
294 std::shared_ptr<impeller::ContextGLES> context_;
301 auto context = std::make_unique<TesterContextGLES>();
302 if (!context->Initialize()) {
303 FML_LOG(ERROR) <<
"Unable to create TesterContextGLESFactory";
static std::unique_ptr< TesterContext > Create()
void RemoveTaskObserver(intptr_t key)
void AddTaskObserver(intptr_t key, const fml::closure &callback)
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static std::shared_ptr< ContextGLES > Create(const Flags &flags, std::unique_ptr< ProcTableGLES > gl, const std::vector< std::shared_ptr< fml::Mapping > > &shader_libraries, bool enable_gpu_tracing)
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
#define FML_LOG(severity)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
EGLDisplay CreateSwangleDisplay()
Creates an EGLDisplay using ANGLE with the Vulkan backend and SwiftShader as the device type.
void SetupSwiftshaderOnce(bool use_swiftshader)
Find and setup the installable client driver for a locally built SwiftShader at known paths....
DEF_SWITCHES_START aot vmservice shared library name
internal::CopyableLambda< T > MakeCopyable(T lambda)