Flutter Engine
The Flutter Engine
Macros | Functions | Variables
FlutterEmbedderGLFW.cc File Reference
#include <cassert>
#include <chrono>
#include <iostream>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <array>
#include <cstring>
#include <list>
#include <unordered_map>
#include "GLFW/glfw3.h"
#include "GLFW/glfw3native.h"
#include "embedder.h"

Go to the source code of this file.

Macros

#define GLFW_EXPOSE_NATIVE_EGL
 
#define GLFW_INCLUDE_GLEXT
 

Functions

void GLFWcursorPositionCallbackAtPhase (GLFWwindow *window, FlutterPointerPhase phase, double x, double y)
 
void GLFWcursorPositionCallback (GLFWwindow *window, double x, double y)
 
void GLFWmouseButtonCallback (GLFWwindow *window, int key, int action, int mods)
 
static void GLFWKeyCallback (GLFWwindow *window, int key, int scancode, int action, int mods)
 
void GLFWwindowSizeCallback (GLFWwindow *window, int width, int height)
 
static std::array< EGLint, 4 > RectToInts (const FlutterRect rect)
 
static void JoinFlutterRect (FlutterRect *rect, FlutterRect additional_rect)
 
static bool HasExtension (const char *extensions, const char *name)
 
bool RunFlutter (GLFWwindow *window, const std::string &project_path, const std::string &icudtl_path)
 
void printUsage ()
 
void GLFW_ErrorCallback (int error, const char *description)
 
int main (int argc, const char *argv[])
 

Variables

static double g_pixelRatio = 1.0
 
static const size_t kInitialWindowWidth = 800
 
static const size_t kInitialWindowHeight = 600
 
static const int kMaxHistorySize = 10
 
static constexpr FlutterViewId kImplicitViewId = 0
 
std::list< FlutterRectdamage_history_
 
std::unordered_map< intptr_t, FlutterRect * > existing_damage_map_
 
EGLDisplay display_
 
EGLSurface surface_
 

Macro Definition Documentation

◆ GLFW_EXPOSE_NATIVE_EGL

#define GLFW_EXPOSE_NATIVE_EGL

Definition at line 9 of file FlutterEmbedderGLFW.cc.

◆ GLFW_INCLUDE_GLEXT

#define GLFW_INCLUDE_GLEXT

Definition at line 10 of file FlutterEmbedderGLFW.cc.

Function Documentation

◆ GLFW_ErrorCallback()

void GLFW_ErrorCallback ( int  error,
const char *  description 
)

Definition at line 286 of file FlutterEmbedderGLFW.cc.

286 {
287 std::cout << "GLFW Error: (" << error << ") " << description << std::endl;
288}
const uint8_t uint32_t uint32_t GError ** error

◆ GLFWcursorPositionCallback()

void GLFWcursorPositionCallback ( GLFWwindow *  window,
double  x,
double  y 
)

Definition at line 68 of file FlutterEmbedderGLFW.cc.

68 {
70}
@ kMove
Definition: embedder.h:985
GLFWwindow * window
Definition: main.cc:45
void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window, FlutterPointerPhase phase, double x, double y)
double y
double x

◆ GLFWcursorPositionCallbackAtPhase()

void GLFWcursorPositionCallbackAtPhase ( GLFWwindow *  window,
FlutterPointerPhase  phase,
double  x,
double  y 
)

Definition at line 47 of file FlutterEmbedderGLFW.cc.

50 {
51 FlutterPointerEvent event = {};
52 event.struct_size = sizeof(event);
53 event.phase = phase;
54 event.x = x * g_pixelRatio;
55 event.y = y * g_pixelRatio;
56 event.timestamp =
57 std::chrono::duration_cast<std::chrono::microseconds>(
58 std::chrono::high_resolution_clock::now().time_since_epoch())
59 .count();
60 // This example only supports a single window, therefore we assume the pointer
61 // event occurred in the only view, the implicit view.
62 event.view_id = kImplicitViewId;
64 reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)), &event,
65 1);
66}
FlutterEngineResult FlutterEngineSendPointerEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPointerEvent *pointers, size_t events_count)
Definition: embedder.cc:2429
FlKeyEvent * event
static double g_pixelRatio
static constexpr FlutterViewId kImplicitViewId
size_t struct_size
The size of this struct. Must be sizeof(FlutterPointerEvent).
Definition: embedder.h:1036

◆ GLFWKeyCallback()

static void GLFWKeyCallback ( GLFWwindow *  window,
int  key,
int  scancode,
int  action,
int  mods 
)
static

Definition at line 91 of file FlutterEmbedderGLFW.cc.

95 {
96 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
97 glfwSetWindowShouldClose(window, GLFW_TRUE);
98 }
99}
#define GLFW_TRUE
Definition: flutter_glfw.cc:33

◆ GLFWmouseButtonCallback()

void GLFWmouseButtonCallback ( GLFWwindow *  window,
int  key,
int  action,
int  mods 
)

Definition at line 72 of file FlutterEmbedderGLFW.cc.

75 {
76 if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) {
77 double x, y;
78 glfwGetCursorPos(window, &x, &y);
80 glfwSetCursorPosCallback(window, GLFWcursorPositionCallback);
81 }
82
83 if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) {
84 double x, y;
85 glfwGetCursorPos(window, &x, &y);
87 glfwSetCursorPosCallback(window, nullptr);
88 }
89}
@ kUp
Definition: embedder.h:973
@ kDown
Definition: embedder.h:980
void GLFWcursorPositionCallback(GLFWwindow *window, double x, double y)

◆ GLFWwindowSizeCallback()

void GLFWwindowSizeCallback ( GLFWwindow *  window,
int  width,
int  height 
)

Definition at line 101 of file FlutterEmbedderGLFW.cc.

101 {
102 FlutterWindowMetricsEvent event = {};
103 event.struct_size = sizeof(event);
104 event.width = width * g_pixelRatio;
105 event.height = height * g_pixelRatio;
106 event.pixel_ratio = g_pixelRatio;
107 // This example only supports a single window, therefore we assume the event
108 // occurred in the only view, the implicit view.
109 event.view_id = kImplicitViewId;
111 reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)),
112 &event);
113}
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition: embedder.cc:2320
int32_t height
int32_t width
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:843

◆ HasExtension()

static bool HasExtension ( const char *  extensions,
const char *  name 
)
static

Definition at line 139 of file FlutterEmbedderGLFW.cc.

139 {
140 const char* r = strstr(extensions, name);
141 auto len = strlen(name);
142 // check that the extension name is terminated by space or null terminator
143 return r != nullptr && (r[len] == ' ' || r[len] == 0);
144}
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ JoinFlutterRect()

static void JoinFlutterRect ( FlutterRect rect,
FlutterRect  additional_rect 
)
static

Definition at line 130 of file FlutterEmbedderGLFW.cc.

130 {
131 rect->left = std::min(rect->left, additional_rect.left);
132 rect->top = std::min(rect->top, additional_rect.top);
133 rect->right = std::max(rect->right, additional_rect.right);
134 rect->bottom = std::max(rect->bottom, additional_rect.bottom);
135}
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
double bottom
Definition: embedder.h:441
double top
Definition: embedder.h:439
double left
Definition: embedder.h:438
double right
Definition: embedder.h:440

◆ main()

int main ( int  argc,
const char *  argv[] 
)

Definition at line 290 of file FlutterEmbedderGLFW.cc.

290 {
291 if (argc != 3) {
292 printUsage();
293 return 1;
294 }
295
296 std::string project_path = argv[1];
297 std::string icudtl_path = argv[2];
298
299 glfwSetErrorCallback(GLFW_ErrorCallback);
300
301 int result = glfwInit();
302 if (result != GLFW_TRUE) {
303 std::cout << "Could not initialize GLFW." << std::endl;
304 return EXIT_FAILURE;
305 }
306
307#if defined(__linux__)
308 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
309#endif
310
311 GLFWwindow* window = glfwCreateWindow(
312 kInitialWindowWidth, kInitialWindowHeight, "Flutter", NULL, NULL);
313 if (window == nullptr) {
314 std::cout << "Could not create GLFW window." << std::endl;
315 return EXIT_FAILURE;
316 }
317
318 int framebuffer_width, framebuffer_height;
319 glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
320 g_pixelRatio = framebuffer_width / kInitialWindowWidth;
321
322 // Get the display and surface variables.
323 display_ = glfwGetEGLDisplay();
324 surface_ = glfwGetEGLSurface(window);
325
326 bool run_result = RunFlutter(window, project_path, icudtl_path);
327 if (!run_result) {
328 std::cout << "Could not run the Flutter engine." << std::endl;
329 return EXIT_FAILURE;
330 }
331
332 glfwSetKeyCallback(window, GLFWKeyCallback);
333 glfwSetWindowSizeCallback(window, GLFWwindowSizeCallback);
334 glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
335
336 while (!glfwWindowShouldClose(window)) {
337 glfwWaitEvents();
338 }
339
340 glfwDestroyWindow(window);
341 glfwTerminate();
342
343 return EXIT_SUCCESS;
344}
GAsyncResult * result
bool RunFlutter(GLFWwindow *window, const std::string &project_path, const std::string &icudtl_path)
void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height)
void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action, int mods)
void printUsage()
void GLFW_ErrorCallback(int error, const char *description)
EGLDisplay display_
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
EGLSurface surface_
static const size_t kInitialWindowHeight
static const size_t kInitialWindowWidth
char ** argv
Definition: library.h:9

◆ printUsage()

void printUsage ( )

Definition at line 280 of file FlutterEmbedderGLFW.cc.

280 {
281 std::cout
282 << "usage: embedder_example_drm <path to project> <path to icudtl.dat>"
283 << std::endl;
284}

◆ RectToInts()

static std::array< EGLint, 4 > RectToInts ( const FlutterRect  rect)
static

Definition at line 117 of file FlutterEmbedderGLFW.cc.

117 {
118 EGLint height;
119 eglQuerySurface(display_, surface_, EGL_HEIGHT, &height);
120
121 std::array<EGLint, 4> res{
122 static_cast<int>(rect.left), height - static_cast<int>(rect.bottom),
123 static_cast<int>(rect.right) - static_cast<int>(rect.left),
124 static_cast<int>(rect.bottom) - static_cast<int>(rect.top)};
125 return res;
126}

◆ RunFlutter()

bool RunFlutter ( GLFWwindow *  window,
const std::string &  project_path,
const std::string &  icudtl_path 
)

Definition at line 146 of file FlutterEmbedderGLFW.cc.

148 {
149 FlutterRendererConfig config = {};
150 config.type = kOpenGL;
151 config.open_gl.struct_size = sizeof(config.open_gl);
152 config.open_gl.make_current = [](void* userdata) -> bool {
153 glfwMakeContextCurrent(static_cast<GLFWwindow*>(userdata));
154 return true;
155 };
156 config.open_gl.clear_current = [](void*) -> bool {
157 glfwMakeContextCurrent(nullptr); // is this even a thing?
158 return true;
159 };
161 [](void* userdata, const FlutterPresentInfo* info) -> bool {
162 // Free the existing damage that was allocated to this frame.
163 if (existing_damage_map_[info->fbo_id] != nullptr) {
164 free(existing_damage_map_[info->fbo_id]);
165 existing_damage_map_[info->fbo_id] = nullptr;
166 }
167
168 // Get list of extensions.
169 const char* extensions = eglQueryString(display_, EGL_EXTENSIONS);
170
171 // Retrieve the set damage region function.
172 PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region_ = nullptr;
173 if (HasExtension(extensions, "EGL_KHR_partial_update")) {
174 set_damage_region_ = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(
175 eglGetProcAddress("eglSetDamageRegionKHR"));
176 }
177
178 // Retrieve the swap buffers with damage function.
179 PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage_ = nullptr;
180 if (HasExtension(extensions, "EGL_EXT_swap_buffers_with_damage")) {
181 swap_buffers_with_damage_ =
182 reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
183 eglGetProcAddress("eglSwapBuffersWithDamageEXT"));
184 } else if (HasExtension(extensions, "EGL_KHR_swap_buffers_with_damage")) {
185 swap_buffers_with_damage_ =
186 reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
187 eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
188 }
189
190 if (set_damage_region_) {
191 // Set the buffer damage as the damage region.
192 auto buffer_rects = RectToInts(info->buffer_damage.damage[0]);
193 set_damage_region_(display_, surface_, buffer_rects.data(), 1);
194 }
195
196 // Add frame damage to damage history
197 damage_history_.push_back(info->frame_damage.damage[0]);
198 if (damage_history_.size() > kMaxHistorySize) {
199 damage_history_.pop_front();
200 }
201
202 if (swap_buffers_with_damage_) {
203 // Swap buffers with frame damage.
204 auto frame_rects = RectToInts(info->frame_damage.damage[0]);
205 return swap_buffers_with_damage_(display_, surface_, frame_rects.data(),
206 1);
207 } else {
208 // If the required extensions for partial repaint were not provided, do
209 // full repaint.
210 return eglSwapBuffers(display_, surface_);
211 }
212 };
213 config.open_gl.fbo_callback = [](void*) -> uint32_t {
214 return 0; // FBO0
215 };
217 [](void* userdata, intptr_t fbo_id,
218 FlutterDamage* existing_damage) -> void {
219 // Given the FBO age, create existing damage region by joining all frame
220 // damages since FBO was last used
221 EGLint age;
222 if (glfwExtensionSupported("GL_EXT_buffer_age") == GLFW_TRUE) {
223 eglQuerySurface(display_, surface_, EGL_BUFFER_AGE_EXT, &age);
224 } else {
225 age = 4; // Virtually no driver should have a swapchain length > 4.
226 }
227
228 existing_damage->num_rects = 1;
229
230 // Allocate the array of rectangles for the existing damage.
231 existing_damage_map_[fbo_id] = static_cast<FlutterRect*>(
232 malloc(sizeof(FlutterRect) * existing_damage->num_rects));
233 existing_damage_map_[fbo_id][0] =
235 existing_damage->damage = existing_damage_map_[fbo_id];
236
237 if (age > 1) {
238 --age;
239 // join up to (age - 1) last rects from damage history
240 for (auto i = damage_history_.rbegin();
241 i != damage_history_.rend() && age > 0; ++i, --age) {
242 if (i == damage_history_.rbegin()) {
243 if (i != damage_history_.rend()) {
244 existing_damage->damage[0] = {i->left, i->top, i->right, i->bottom};
245 }
246 } else {
247 JoinFlutterRect(&(existing_damage->damage[0]), *i);
248 }
249 }
250 }
251 };
252 config.open_gl.gl_proc_resolver = [](void*, const char* name) -> void* {
253 return reinterpret_cast<void*>(glfwGetProcAddress(name));
254 };
255 config.open_gl.fbo_reset_after_present = true;
256
257 // This directory is generated by `flutter build bundle`.
258 std::string assets_path = project_path + "/build/flutter_assets";
260 .struct_size = sizeof(FlutterProjectArgs),
261 .assets_path = assets_path.c_str(),
262 .icu_data_path =
263 icudtl_path.c_str(), // Find this in your bin/cache directory.
264 };
265 FlutterEngine engine = nullptr;
267 FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, // renderer
268 &args, window, &engine);
269 if (result != kSuccess || engine == nullptr) {
270 std::cout << "Could not run the Flutter Engine." << std::endl;
271 return false;
272 }
273
274 glfwSetWindowUserPointer(window, engine);
276
277 return true;
278}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
FlutterEngineResult FlutterEngineRun(size_t version, const FlutterRendererConfig *config, const FlutterProjectArgs *args, void *user_data, FLUTTER_API_SYMBOL(FlutterEngine) *engine_out)
Initialize and run a Flutter engine instance and return a handle to it. This is a convenience method ...
Definition: embedder.cc:1715
@ kOpenGL
Definition: embedder.h:80
FlutterEngineResult
Definition: embedder.h:72
@ kSuccess
Definition: embedder.h:73
#define FLUTTER_ENGINE_VERSION
Definition: embedder.h:70
FlutterEngine engine
Definition: main.cc:68
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static std::array< EGLint, 4 > RectToInts(const FlutterRect rect)
static const int kMaxHistorySize
std::unordered_map< intptr_t, FlutterRect * > existing_damage_map_
static void JoinFlutterRect(FlutterRect *rect, FlutterRect additional_rect)
std::list< FlutterRect > damage_history_
static bool HasExtension(const char *extensions, const char *name)
void * malloc(size_t size)
Definition: allocation.cc:19
A structure to represent a damage region.
Definition: embedder.h:460
ProcResolver gl_proc_resolver
Definition: embedder.h:554
BoolCallback make_current
Definition: embedder.h:516
BoolPresentInfoCallback present_with_info
Definition: embedder.h:578
UIntCallback fbo_callback
Definition: embedder.h:530
size_t struct_size
The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig).
Definition: embedder.h:515
FlutterFrameBufferWithDamageCallback populate_existing_damage
Definition: embedder.h:592
BoolCallback clear_current
Definition: embedder.h:517
A structure to represent a rectangle.
Definition: embedder.h:437
FlutterOpenGLRendererConfig open_gl
Definition: embedder.h:829
FlutterRendererType type
Definition: embedder.h:827

Variable Documentation

◆ damage_history_

std::list<FlutterRect> damage_history_

Definition at line 33 of file FlutterEmbedderGLFW.cc.

◆ display_

EGLDisplay display_

Definition at line 38 of file FlutterEmbedderGLFW.cc.

◆ existing_damage_map_

std::unordered_map<intptr_t, FlutterRect*> existing_damage_map_

Definition at line 36 of file FlutterEmbedderGLFW.cc.

◆ g_pixelRatio

double g_pixelRatio = 1.0
static

Definition at line 23 of file FlutterEmbedderGLFW.cc.

◆ kImplicitViewId

constexpr FlutterViewId kImplicitViewId = 0
staticconstexpr

Definition at line 29 of file FlutterEmbedderGLFW.cc.

◆ kInitialWindowHeight

const size_t kInitialWindowHeight = 600
static

Definition at line 25 of file FlutterEmbedderGLFW.cc.

◆ kInitialWindowWidth

const size_t kInitialWindowWidth = 800
static

Definition at line 24 of file FlutterEmbedderGLFW.cc.

◆ kMaxHistorySize

const int kMaxHistorySize = 10
static

Definition at line 28 of file FlutterEmbedderGLFW.cc.

◆ surface_

EGLSurface surface_

Definition at line 39 of file FlutterEmbedderGLFW.cc.