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/entity/gles3/entity_shaders_gles.h"
21 #include "impeller/entity/gles3/framebuffer_blend_shaders_gles.h"
22 #include "impeller/entity/gles3/modern_shaders_gles.h"
23 #include "impeller/fixtures/gles/fixtures_shaders_gles.h"
24 #include "impeller/fixtures/gles/modern_fixtures_shaders_gles.h"
25 #include "impeller/fixtures/gles3/fixtures_shaders_gles.h"
26 #include "impeller/fixtures/gles3/modern_fixtures_shaders_gles.h"
27 #include "impeller/playground/imgui/gles/imgui_shaders_gles.h"
28 #include "impeller/playground/imgui/gles3/imgui_shaders_gles.h"
31 
32 namespace impeller {
33 
35  public:
36  ReactorWorker() = default;
37 
38  // |ReactorGLES::Worker|
40  const ReactorGLES& reactor) const override {
41  ReaderLock lock(mutex_);
42  auto found = reactions_allowed_.find(std::this_thread::get_id());
43  if (found == reactions_allowed_.end()) {
44  return false;
45  }
46  return found->second;
47  }
48 
50  WriterLock lock(mutex_);
51  reactions_allowed_[std::this_thread::get_id()] = allowed;
52  }
53 
54  private:
55  mutable RWMutex mutex_;
56  std::map<std::thread::id, bool> reactions_allowed_ IPLR_GUARDED_BY(mutex_);
57 
58  ReactorWorker(const ReactorWorker&) = delete;
59 
60  ReactorWorker& operator=(const ReactorWorker&) = delete;
61 };
62 
63 void PlaygroundImplGLES::DestroyWindowHandle(WindowHandle handle) {
64  if (!handle) {
65  return;
66  }
67  ::glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(handle));
68 }
69 
71  : PlaygroundImpl(switches),
72  handle_(nullptr, &DestroyWindowHandle),
73  worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())),
74  use_angle_(switches.use_angle) {
75  if (use_angle_) {
76 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
77  angle_glesv2_ = dlopen("libGLESv2.dylib", RTLD_LAZY);
78 #endif
79  FML_CHECK(angle_glesv2_ != nullptr);
80  }
81 
82  ::glfwDefaultWindowHints();
83 
84 #if FML_OS_MACOSX
85  FML_CHECK(use_angle_) << "Must use Angle on macOS for OpenGL ES.";
86  ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
87 #endif // FML_OS_MACOSX
88 #if FML_OS_LINUX
89  // Use EGL even on X11 then the client can select the GLES implementation
90  // by defining __EGL_VENDOR_LIBRARY_FILENAMES
91  ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
92 #endif
93  ::glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
94  ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
95  ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
96  ::glfwWindowHint(GLFW_RED_BITS, 8);
97  ::glfwWindowHint(GLFW_GREEN_BITS, 8);
98  ::glfwWindowHint(GLFW_BLUE_BITS, 8);
99  ::glfwWindowHint(GLFW_ALPHA_BITS, 8);
100  ::glfwWindowHint(GLFW_DEPTH_BITS, 32); // 32 bit depth buffer
101  ::glfwWindowHint(GLFW_STENCIL_BITS, 8); // 8 bit stencil buffer
102  ::glfwWindowHint(GLFW_SAMPLES, 4); // 4xMSAA
103 
104  ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
105 #ifndef NDEBUG
106  ::glfwWindowHint(GLFW_CONTEXT_DEBUG, GLFW_TRUE);
107 #endif
108 
109  auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
110 
111  ::glfwMakeContextCurrent(window);
112  worker_->SetReactionsAllowedOnCurrentThread(true);
113 
114  handle_.reset(window);
115 }
116 
118 
119 static std::vector<std::shared_ptr<fml::Mapping>>
121  if (is_gles3) {
122  return {
123  std::make_shared<fml::NonOwnedMapping>(
124  impeller_entity_shaders_gles3_data,
125  impeller_entity_shaders_gles3_length),
126  std::make_shared<fml::NonOwnedMapping>(
127  impeller_modern_shaders_gles3_data,
128  impeller_modern_shaders_gles3_length),
129  std::make_shared<fml::NonOwnedMapping>(
130  impeller_framebuffer_blend_shaders_gles3_data,
131  impeller_framebuffer_blend_shaders_gles3_length),
132  std::make_shared<fml::NonOwnedMapping>(
133  impeller_fixtures_shaders_gles3_data,
134  impeller_fixtures_shaders_gles3_length),
135  std::make_shared<fml::NonOwnedMapping>(
136  impeller_modern_fixtures_shaders_gles3_data,
137  impeller_modern_fixtures_shaders_gles3_length),
138  std::make_shared<fml::NonOwnedMapping>(
139  impeller_imgui_shaders_gles3_data,
140  impeller_imgui_shaders_gles3_length),
141  };
142  }
143  return {
144  std::make_shared<fml::NonOwnedMapping>(
145  impeller_entity_shaders_gles_data,
146  impeller_entity_shaders_gles_length),
147  std::make_shared<fml::NonOwnedMapping>(
148  impeller_modern_shaders_gles_data,
149  impeller_modern_shaders_gles_length),
150  std::make_shared<fml::NonOwnedMapping>(
151  impeller_framebuffer_blend_shaders_gles_data,
152  impeller_framebuffer_blend_shaders_gles_length),
153  std::make_shared<fml::NonOwnedMapping>(
154  impeller_fixtures_shaders_gles_data,
155  impeller_fixtures_shaders_gles_length),
156  std::make_shared<fml::NonOwnedMapping>(
157  impeller_modern_fixtures_shaders_gles_data,
158  impeller_modern_fixtures_shaders_gles_length),
159  std::make_shared<fml::NonOwnedMapping>(
160  impeller_imgui_shaders_gles_data, impeller_imgui_shaders_gles_length),
161  };
162 }
163 
164 // |PlaygroundImpl|
165 std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
166  auto gl = std::make_unique<ProcTableGLES>(CreateGLProcAddressResolver());
167  if (!gl->IsValid()) {
168  FML_LOG(ERROR) << "Proc table when creating a playground was invalid.";
169  return nullptr;
170  }
171 
172  if (gl->GetDescription()->HasDebugExtension()) {
173  gl->DebugMessageCallbackKHR(
174  +[](GLenum /* source */, GLenum message_type, GLuint /* message_id */,
175  GLenum /* severity */, GLsizei /* length */, const GLchar* message,
176  const void* /* user_param */) {
177  switch (message_type) {
178  case GL_DEBUG_TYPE_ERROR_KHR:
179  FML_LOG(ERROR) << "GL Error: " << message;
180  return;
181  default:
182  return;
183  }
184  },
185  nullptr);
186 
187 #ifndef NDEBUG
188  gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
189 #endif
190  }
191  bool is_gles3 = gl->GetDescription()->GetGlVersion().IsAtLeast(Version(3));
192  auto context =
193  ContextGLES::Create(switches_.flags, std::move(gl),
194  ShaderLibraryMappingsForPlayground(is_gles3), true);
195  if (!context) {
196  FML_LOG(ERROR) << "Could not create context.";
197  return nullptr;
198  }
199 
200  auto worker_id = context->AddReactorWorker(worker_);
201  if (!worker_id.has_value()) {
202  FML_LOG(ERROR) << "Could not add reactor worker.";
203  return nullptr;
204  }
205  return context;
206 }
207 
208 // |PlaygroundImpl|
210 PlaygroundImplGLES::CreateGLProcAddressResolver() const {
211  return use_angle_ ? [](const char* name) -> void* {
212  void* symbol = nullptr;
213 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
214  void* angle_glesv2 = dlopen("libGLESv2.dylib", RTLD_LAZY);
215  symbol = dlsym(angle_glesv2, name);
216 #endif
217  FML_CHECK(symbol);
218  return symbol;
219  }
220  : [](const char* name) -> void* {
221  return reinterpret_cast<void*>(::glfwGetProcAddress(name));
222  };
223 }
224 
225 // |PlaygroundImpl|
226 PlaygroundImpl::WindowHandle PlaygroundImplGLES::GetWindowHandle() const {
227  return handle_.get();
228 }
229 
230 // |PlaygroundImpl|
231 std::unique_ptr<Surface> PlaygroundImplGLES::AcquireSurfaceFrame(
232  std::shared_ptr<Context> context) {
233  auto window = reinterpret_cast<GLFWwindow*>(GetWindowHandle());
234  int width = 0;
235  int height = 0;
236  ::glfwGetFramebufferSize(window, &width, &height);
237  if (width <= 0 || height <= 0) {
238  return nullptr;
239  }
240  SurfaceGLES::SwapCallback swap_callback = [window]() -> bool {
241  ::glfwSwapBuffers(window);
242  return true;
243  };
244  return SurfaceGLES::WrapFBO(context, //
245  swap_callback, //
246  0u, //
248  ISize::MakeWH(width, height) //
249  );
250 }
251 
253  const std::shared_ptr<Capabilities>& capabilities) {
254  return fml::Status(
255  fml::StatusCode::kUnimplemented,
256  "PlaygroundImplGLES doesn't support setting the capabilities.");
257 }
258 
259 RuntimeStageBackend PlaygroundImplGLES::GetRuntimeStageBackend() const {
260  const auto gl =
261  std::make_unique<ProcTableGLES>(CreateGLProcAddressResolver());
262  if (!gl->IsValid()) {
263  FML_LOG(ERROR) << "Proc table was invalid. Assuming baseline OpenGL ES";
265  }
266  bool is_gles3 = gl->GetDescription()->GetGlVersion().IsAtLeast(Version(3));
267  return is_gles3 ? RuntimeStageBackend::kOpenGLES3
269 }
270 
271 } // 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:105
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(bool is_gles3)
Definition: comparable.h:93
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43