7#define IMPELLER_PLAYGROUND_SUPPORTS_ANGLE FML_OS_MACOSX
9#if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
13#define GLFW_INCLUDE_NONE
14#include "third_party/glfw/include/GLFW/glfw3.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"
36 auto found = reactions_allowed_.find(std::this_thread::get_id());
37 if (found == reactions_allowed_.end()) {
45 reactions_allowed_[std::this_thread::get_id()] = allowed;
49 mutable RWMutex mutex_;
50 std::map<std::thread::id, bool> reactions_allowed_
IPLR_GUARDED_BY(mutex_);
57void PlaygroundImplGLES::DestroyWindowHandle(WindowHandle handle) {
61 ::glfwDestroyWindow(
reinterpret_cast<GLFWwindow*
>(handle));
66 handle_(nullptr, &DestroyWindowHandle),
68 use_angle_(switches.use_angle) {
70#if IMPELLER_PLAYGROUND_SUPPORTS_ANGLE
71 angle_glesv2_ = dlopen(
"libGLESv2.dylib", RTLD_LAZY);
76 ::glfwDefaultWindowHints();
79 FML_CHECK(use_angle_) <<
"Must use Angle on macOS for OpenGL ES.";
80 ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
85 ::glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
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);
95 ::glfwWindowHint(GLFW_STENCIL_BITS, 8);
96 ::glfwWindowHint(GLFW_SAMPLES, 4);
100 ::glfwWindowHint(GLFW_CONTEXT_DEBUG,
GLFW_TRUE);
103 auto window = ::glfwCreateWindow(1, 1,
"Test",
nullptr,
nullptr);
105 ::glfwMakeContextCurrent(
window);
106 worker_->SetReactionsAllowedOnCurrentThread(
true);
113static std::vector<std::shared_ptr<fml::Mapping>>
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),
137std::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.";
144 if (gl->GetDescription()->HasDebugExtension()) {
145 gl->DebugMessageCallbackKHR(
146 +[](GLenum , GLenum message_type, GLuint ,
147 GLenum , GLsizei ,
const GLchar*
message,
149 switch (message_type) {
150 case GL_DEBUG_TYPE_ERROR_KHR:
160 gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
167 FML_LOG(ERROR) <<
"Could not create context.";
171 auto worker_id = context->AddReactorWorker(worker_);
172 if (!worker_id.has_value()) {
173 FML_LOG(ERROR) <<
"Could not add reactor worker.";
181PlaygroundImplGLES::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);
191 : [](
const char*
name) ->
void* {
192 return reinterpret_cast<void*
>(::glfwGetProcAddress(
name));
198 return handle_.get();
202std::unique_ptr<Surface> PlaygroundImplGLES::AcquireSurfaceFrame(
203 std::shared_ptr<Context> context) {
204 auto window =
reinterpret_cast<GLFWwindow*
>(GetWindowHandle());
212 ::glfwSwapBuffers(
window);
224 const std::shared_ptr<Capabilities>& capabilities) {
227 "PlaygroundImplGLES doesn't support setting the capabilities.");
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)
std::function< void *(const char *proc_name)> GLProcAddressResolver
bool CanReactorReactOnCurrentThreadNow(const ReactorGLES &reactor) const override
Determines the ability of the worker to service a reaction on the current thread. The OpenGL context ...
void SetReactionsAllowedOnCurrentThread(bool allowed)
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...
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
static std::unique_ptr< Surface > WrapFBO(const std::shared_ptr< Context > &context, SwapCallback swap_callback, GLuint fbo, PixelFormat color_format, ISize fbo_size)
std::function< bool(void)> SwapCallback
#define FML_LOG(severity)
#define FML_CHECK(condition)
static std::vector< std::shared_ptr< fml::Mapping > > ShaderLibraryMappingsForPlayground()
static constexpr TSize MakeWH(Type width, Type height)
#define IPLR_GUARDED_BY(x)