| 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
5 #include "impeller/playground/backend/gles/playground_impl_gles.h"
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"
23 #include "impeller/renderer/backend/gles/context_gles.h"
24 #include "impeller/renderer/backend/gles/surface_gles.h"
25
26 namespace impeller {
27
28 class PlaygroundImplGLES::ReactorWorker final : public ReactorGLES::Worker {
29 public:
30 ReactorWorker() = default;
31
32 // |ReactorGLES::Worker|
33 bool CanReactorReactOnCurrentThreadNow(
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
43 void SetReactionsAllowedOnCurrentThread(bool allowed) {
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
64 PlaygroundImplGLES::PlaygroundImplGLES(PlaygroundSwitches switches)
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 #if FML_OS_LINUX
83 // Use EGL even on X11 then the client can select the GLES implementation
84 // by defining __EGL_VENDOR_LIBRARY_FILENAMES
85 ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
86 #endif
87 ::glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
88 ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
89 ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
90 ::glfwWindowHint(GLFW_RED_BITS, 8);
91 ::glfwWindowHint(GLFW_GREEN_BITS, 8);
92 ::glfwWindowHint(GLFW_BLUE_BITS, 8);
93 ::glfwWindowHint(GLFW_ALPHA_BITS, 8);
94 ::glfwWindowHint(GLFW_DEPTH_BITS, 32); // 32 bit depth buffer
95 ::glfwWindowHint(GLFW_STENCIL_BITS, 8); // 8 bit stencil buffer
96 ::glfwWindowHint(GLFW_SAMPLES, 4); // 4xMSAA
97
98 ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
99 #ifndef NDEBUG
100 ::glfwWindowHint(GLFW_CONTEXT_DEBUG, GLFW_TRUE);
101 #endif
102
103 auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
104
105 ::glfwMakeContextCurrent(window);
106 worker_->SetReactionsAllowedOnCurrentThread(true);
107
108 handle_.reset(window);
109 }
110
111 PlaygroundImplGLES::~PlaygroundImplGLES() = default;
112
113 static std::vector<std::shared_ptr<fml::Mapping>>
114 ShaderLibraryMappingsForPlayground() {
115 return {
116 std::make_shared<fml::NonOwnedMapping>(
117 impeller_entity_shaders_gles_data,
118 impeller_entity_shaders_gles_length),
119 std::make_shared<fml::NonOwnedMapping>(
120 impeller_modern_shaders_gles_data,
121 impeller_modern_shaders_gles_length),
122 std::make_shared<fml::NonOwnedMapping>(
123 impeller_framebuffer_blend_shaders_gles_data,
124 impeller_framebuffer_blend_shaders_gles_length),
125 std::make_shared<fml::NonOwnedMapping>(
126 impeller_fixtures_shaders_gles_data,
127 impeller_fixtures_shaders_gles_length),
128 std::make_shared<fml::NonOwnedMapping>(
129 impeller_modern_fixtures_shaders_gles_data,
130 impeller_modern_fixtures_shaders_gles_length),
131 std::make_shared<fml::NonOwnedMapping>(
132 impeller_imgui_shaders_gles_data, impeller_imgui_shaders_gles_length),
133 };
134 }
135
136 // |PlaygroundImpl|
137 std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
138 auto gl = std::make_unique<ProcTableGLES>(CreateGLProcAddressResolver());
139 if (!gl->IsValid()) {
140 FML_LOG(ERROR) << "Proc table when creating a playground was invalid.";
141 return nullptr;
142 }
143
144 if (gl->GetDescription()->HasDebugExtension()) {
145 gl->DebugMessageCallbackKHR(
146 +[](GLenum /* source */, GLenum message_type, GLuint /* message_id */,
147 GLenum /* severity */, GLsizei /* length */, const GLchar* message,
148 const void* /* user_param */) {
149 switch (message_type) {
150 case GL_DEBUG_TYPE_ERROR_KHR:
151 FML_LOG(ERROR) << "GL Error: " << message;
152 return;
153 default:
154 return;
155 }
156 },
157 nullptr);
158
159 #ifndef NDEBUG
160 gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
161 #endif
162 }
163 auto context =
164 ContextGLES::Create(switches_.flags, std::move(gl),
165 ShaderLibraryMappingsForPlayground(), true);
166 if (!context) {
167 FML_LOG(ERROR) << "Could not create context.";
168 return nullptr;
169 }
170
171 auto worker_id = context->AddReactorWorker(worker_);
172 if (!worker_id.has_value()) {
173 FML_LOG(ERROR) << "Could not add reactor worker.";
174 return nullptr;
175 }
176 return context;
177 }
178
179 // |PlaygroundImpl|
180 Playground::GLProcAddressResolver
181 PlaygroundImplGLES::CreateGLProcAddressResolver() const {
182 return use_angle_ ? [](const char* name) -> void* {
183 void* symbol = nullptr;
184 #if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
185 void* angle_glesv2 = dlopen("libGLESv2.dylib", RTLD_LAZY);
186 symbol = dlsym(angle_glesv2, name);
187 #endif
188 FML_CHECK(symbol);
189 return symbol;
190 }
191 : [](const char* name) -> void* {
192 return reinterpret_cast<void*>(::glfwGetProcAddress(name));
193 };
194 }
195
196 // |PlaygroundImpl|
197 PlaygroundImpl::WindowHandle PlaygroundImplGLES::GetWindowHandle() const {
198 return handle_.get();
199 }
200
201 // |PlaygroundImpl|
202 std::unique_ptr<Surface> PlaygroundImplGLES::AcquireSurfaceFrame(
203 std::shared_ptr<Context> context) {
204 auto window = reinterpret_cast<GLFWwindow*>(GetWindowHandle());
205 int width = 0;
206 int height = 0;
207 ::glfwGetFramebufferSize(window, &width, &height);
208 if (width <= 0 || height <= 0) {
209 return nullptr;
210 }
211 SurfaceGLES::SwapCallback swap_callback = [window]() -> bool {
212 ::glfwSwapBuffers(window);
213 return true;
214 };
215 return SurfaceGLES::WrapFBO(context, //
216 swap_callback, //
217 0u, //
218 PixelFormat::kR8G8B8A8UNormInt, //
219 ISize::MakeWH(width, height) //
220 );
221 }
222
223 fml::Status PlaygroundImplGLES::SetCapabilities(
224 const std::shared_ptr<Capabilities>& capabilities) {
225 return fml::Status(
226 fml::StatusCode::kUnimplemented,
227 "PlaygroundImplGLES doesn't support setting the capabilities.");
228 }
229
230 } // namespace impeller
impeller::ContextGLES::Create
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
impeller::Playground::GLProcAddressResolver
std::function< void *(const char *proc_name)> GLProcAddressResolver
Definition: playground.h:118
impeller::PlaygroundImplGLES::ReactorWorker
Definition: playground_impl_gles.cc:28
impeller::PlaygroundImplGLES::ReactorWorker::ReactorWorker
ReactorWorker()=default
impeller::PlaygroundImplGLES::ReactorWorker::CanReactorReactOnCurrentThreadNow
bool CanReactorReactOnCurrentThreadNow(const ReactorGLES &reactor) const override
Determines the ability of the worker to service a reaction on the current thread. The OpenGL context ...
Definition: playground_impl_gles.cc:33
impeller::PlaygroundImplGLES::ReactorWorker::SetReactionsAllowedOnCurrentThread
void SetReactionsAllowedOnCurrentThread(bool allowed)
Definition: playground_impl_gles.cc:43
impeller::PlaygroundImplGLES::PlaygroundImplGLES
PlaygroundImplGLES(PlaygroundSwitches switches)
Definition: playground_impl_gles.cc:64
impeller::PlaygroundImplGLES::~PlaygroundImplGLES
~PlaygroundImplGLES()
impeller::PlaygroundImplGLES::SetCapabilities
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities) override
Definition: playground_impl_gles.cc:223
impeller::PlaygroundImpl
Definition: playground_impl.h:18
impeller::PlaygroundImpl::WindowHandle
void * WindowHandle
Definition: playground_impl.h:25
impeller::PlaygroundImpl::switches_
const PlaygroundSwitches switches_
Definition: playground_impl.h:46
impeller::ReactorGLES::Worker
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
Definition: reactor_gles.h:69
impeller::ReactorGLES
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:57
impeller::ReaderLock
Definition: thread.h:92
impeller::SurfaceGLES::WrapFBO
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
impeller::SurfaceGLES::SwapCallback
std::function< bool(void)> SwapCallback
Definition: surface_gles.h:19
impeller::WriterLock
Definition: thread.h:113
impeller
Definition: allocation.cc:12
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::ShaderLibraryMappingsForPlayground
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
Definition: playground_impl_gles.cc:114
std
Definition: comparable.h:95
playground_impl_gles.h
context_gles.h
surface_gles.h
impeller::PlaygroundSwitches
Definition: switches.h:16
impeller::PlaygroundSwitches::flags
Flags flags
Definition: switches.h:38
impeller::TSize::MakeWH
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43