Flutter Impeller
playground_impl_gles.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #define IMPELLER_PLAYGROUND_SUPPORTS_ANGLE FML_OS_MACOSX
8 
9 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
10 #include <dlfcn.h>
11 #endif
12 
13 #define GLFW_INCLUDE_NONE
14 #include "third_party/glfw/include/GLFW/glfw3.h"
15 
16 #include "flutter/fml/build_config.h"
17 #include "impeller/entity/gles/entity_shaders_gles.h"
18 #include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
19 #include "impeller/entity/gles/modern_shaders_gles.h"
20 #include "impeller/fixtures/gles/fixtures_shaders_gles.h"
21 #include "impeller/fixtures/gles/modern_fixtures_shaders_gles.h"
22 #include "impeller/playground/imgui/gles/imgui_shaders_gles.h"
25 
26 namespace impeller {
27 
29  public:
30  ReactorWorker() = default;
31 
32  // |ReactorGLES::Worker|
34  const ReactorGLES& reactor) const override {
35  ReaderLock lock(mutex_);
36  auto found = reactions_allowed_.find(std::this_thread::get_id());
37  if (found == reactions_allowed_.end()) {
38  return false;
39  }
40  return found->second;
41  }
42 
44  WriterLock lock(mutex_);
45  reactions_allowed_[std::this_thread::get_id()] = allowed;
46  }
47 
48  private:
49  mutable RWMutex mutex_;
50  std::map<std::thread::id, bool> reactions_allowed_ IPLR_GUARDED_BY(mutex_);
51 
52  ReactorWorker(const ReactorWorker&) = delete;
53 
54  ReactorWorker& operator=(const ReactorWorker&) = delete;
55 };
56 
57 void PlaygroundImplGLES::DestroyWindowHandle(WindowHandle handle) {
58  if (!handle) {
59  return;
60  }
61  ::glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(handle));
62 }
63 
65  : PlaygroundImpl(switches),
66  handle_(nullptr, &DestroyWindowHandle),
67  worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())),
68  use_angle_(switches.use_angle) {
69  if (use_angle_) {
70 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
71  angle_glesv2_ = dlopen("libGLESv2.dylib", RTLD_LAZY);
72 #endif
73  FML_CHECK(angle_glesv2_ != nullptr);
74  }
75 
76  ::glfwDefaultWindowHints();
77 
78 #if FML_OS_MACOSX
79  FML_CHECK(use_angle_) << "Must use Angle on macOS for OpenGL ES.";
80  ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
81 #endif // FML_OS_MACOSX
82  ::glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
83  ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
84  ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
85  ::glfwWindowHint(GLFW_RED_BITS, 8);
86  ::glfwWindowHint(GLFW_GREEN_BITS, 8);
87  ::glfwWindowHint(GLFW_BLUE_BITS, 8);
88  ::glfwWindowHint(GLFW_ALPHA_BITS, 8);
89  ::glfwWindowHint(GLFW_DEPTH_BITS, 32); // 32 bit depth buffer
90  ::glfwWindowHint(GLFW_STENCIL_BITS, 8); // 8 bit stencil buffer
91  ::glfwWindowHint(GLFW_SAMPLES, 4); // 4xMSAA
92 
93  ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
94 
95  auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
96 
97  ::glfwMakeContextCurrent(window);
98  worker_->SetReactionsAllowedOnCurrentThread(true);
99 
100  handle_.reset(window);
101 }
102 
104 
105 static std::vector<std::shared_ptr<fml::Mapping>>
107  return {
108  std::make_shared<fml::NonOwnedMapping>(
109  impeller_entity_shaders_gles_data,
110  impeller_entity_shaders_gles_length),
111  std::make_shared<fml::NonOwnedMapping>(
112  impeller_modern_shaders_gles_data,
113  impeller_modern_shaders_gles_length),
114  std::make_shared<fml::NonOwnedMapping>(
115  impeller_framebuffer_blend_shaders_gles_data,
116  impeller_framebuffer_blend_shaders_gles_length),
117  std::make_shared<fml::NonOwnedMapping>(
118  impeller_fixtures_shaders_gles_data,
119  impeller_fixtures_shaders_gles_length),
120  std::make_shared<fml::NonOwnedMapping>(
121  impeller_modern_fixtures_shaders_gles_data,
122  impeller_modern_fixtures_shaders_gles_length),
123  std::make_shared<fml::NonOwnedMapping>(
124  impeller_imgui_shaders_gles_data, impeller_imgui_shaders_gles_length),
125  };
126 }
127 
128 // |PlaygroundImpl|
129 std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
130  auto gl = std::make_unique<ProcTableGLES>(CreateGLProcAddressResolver());
131  if (!gl->IsValid()) {
132  FML_LOG(ERROR) << "Proc table when creating a playground was invalid.";
133  return nullptr;
134  }
135 
136  auto context =
137  ContextGLES::Create(switches_.flags, std::move(gl),
139  if (!context) {
140  FML_LOG(ERROR) << "Could not create context.";
141  return nullptr;
142  }
143 
144  auto worker_id = context->AddReactorWorker(worker_);
145  if (!worker_id.has_value()) {
146  FML_LOG(ERROR) << "Could not add reactor worker.";
147  return nullptr;
148  }
149  return context;
150 }
151 
152 // |PlaygroundImpl|
154 PlaygroundImplGLES::CreateGLProcAddressResolver() const {
155  return use_angle_ ? [](const char* name) -> void* {
156  void* symbol = nullptr;
157 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
158  void* angle_glesv2 = dlopen("libGLESv2.dylib", RTLD_LAZY);
159  symbol = dlsym(angle_glesv2, name);
160 #endif
161  FML_CHECK(symbol);
162  return symbol;
163  }
164  : [](const char* name) -> void* {
165  return reinterpret_cast<void*>(::glfwGetProcAddress(name));
166  };
167 }
168 
169 // |PlaygroundImpl|
170 PlaygroundImpl::WindowHandle PlaygroundImplGLES::GetWindowHandle() const {
171  return handle_.get();
172 }
173 
174 // |PlaygroundImpl|
175 std::unique_ptr<Surface> PlaygroundImplGLES::AcquireSurfaceFrame(
176  std::shared_ptr<Context> context) {
177  auto window = reinterpret_cast<GLFWwindow*>(GetWindowHandle());
178  int width = 0;
179  int height = 0;
180  ::glfwGetFramebufferSize(window, &width, &height);
181  if (width <= 0 || height <= 0) {
182  return nullptr;
183  }
184  SurfaceGLES::SwapCallback swap_callback = [window]() -> bool {
185  ::glfwSwapBuffers(window);
186  return true;
187  };
188  return SurfaceGLES::WrapFBO(context, //
189  swap_callback, //
190  0u, //
192  ISize::MakeWH(width, height) //
193  );
194 }
195 
197  const std::shared_ptr<Capabilities>& capabilities) {
198  return fml::Status(
199  fml::StatusCode::kUnimplemented,
200  "PlaygroundImplGLES doesn't support setting the capabilities.");
201 }
202 
203 } // namespace impeller
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)
Definition: context_gles.cc:21
std::function< void *(const char *proc_name)> GLProcAddressResolver
Definition: playground.h:118
bool CanReactorReactOnCurrentThreadNow(const ReactorGLES &reactor) const override
Determines the ability of the worker to service a reaction on the current thread. The OpenGL context ...
PlaygroundImplGLES(PlaygroundSwitches switches)
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
const PlaygroundSwitches switches_
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
Definition: reactor_gles.h:69
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:57
static std::unique_ptr< Surface > WrapFBO(const std::shared_ptr< Context > &context, SwapCallback swap_callback, GLuint fbo, PixelFormat color_format, ISize fbo_size)
Definition: surface_gles.cc:14
std::function< bool(void)> SwapCallback
Definition: surface_gles.h:19
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
Definition: comparable.h:95
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43