CWaylandOpenGLDriver.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #include "CWaylandOpenGLDriver.h"
  2. #include "WallpaperEngine/Application/CWallpaperApplication.h"
  3. #include <FreeImage.h>
  4. #include "common.h"
  5. #define class _class
  6. #define namespace _namespace
  7. #define static
  8. extern "C" {
  9. #include "xdg-shell-protocol.h"
  10. #include "wlr-layer-shell-unstable-v1-protocol.h"
  11. }
  12. #undef class
  13. #undef namespace
  14. #undef static
  15. #include <string.h>
  16. using namespace WallpaperEngine::Render::Drivers;
  17. static void handlePointerEnter(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
  18. const auto PDRIVER = (CWaylandOpenGLDriver*)data;
  19. const auto PLS = PDRIVER->surfaceToLS(surface);
  20. PDRIVER->lastLSInFocus = PLS;
  21. wl_surface_set_buffer_scale(PLS->cursorSurface, PLS->output->scale);
  22. wl_surface_attach(PLS->cursorSurface, wl_cursor_image_get_buffer(PLS->pointer->images[0]), 0, 0);
  23. wl_pointer_set_cursor(wl_pointer, serial, PLS->cursorSurface, PLS->pointer->images[0]->hotspot_x, PLS->pointer->images[0]->hotspot_y);
  24. wl_surface_commit(PLS->cursorSurface);
  25. }
  26. static void handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface) {
  27. // ignored
  28. }
  29. static void handlePointerAxis(void* data, wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
  30. // ignored
  31. }
  32. static void handlePointerMotion(void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
  33. auto x = wl_fixed_to_double(surface_x);
  34. auto y = wl_fixed_to_double(surface_y);
  35. const auto PDRIVER = (CWaylandOpenGLDriver*)data;
  36. if (!PDRIVER->lastLSInFocus)
  37. return;
  38. PDRIVER->lastLSInFocus->mousePos = {x * PDRIVER->lastLSInFocus->output->scale, y * PDRIVER->lastLSInFocus->output->scale};
  39. }
  40. static void handlePointerButton(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) {
  41. // ignored
  42. }
  43. const struct wl_pointer_listener pointerListener = { .enter = handlePointerEnter, .leave = handlePointerLeave, .motion = handlePointerMotion, .button = handlePointerButton, .axis = handlePointerAxis };
  44. static void handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities) {
  45. if (capabilities & WL_SEAT_CAPABILITY_POINTER)
  46. wl_pointer_add_listener(wl_seat_get_pointer(wl_seat), &pointerListener, data);
  47. }
  48. const struct wl_seat_listener seatListener = { .capabilities = handleCapabilities };
  49. static void geometry(void* data, wl_output* output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model,
  50. int32_t transform) {
  51. // ignored
  52. }
  53. static void mode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
  54. const auto PMONITOR = (SWaylandOutput*)data;
  55. PMONITOR->size = {width, height};
  56. PMONITOR->lsSize = {width, height};
  57. if (PMONITOR->layerSurface.get())
  58. PMONITOR->driver->resizeLSSurfaceEGL(PMONITOR->layerSurface.get());
  59. if (PMONITOR->initialized)
  60. PMONITOR->driver->wallpaperApplication->getOutput()->reset();
  61. }
  62. static void done(void* data, wl_output* wl_output) {
  63. const auto PMONITOR = (SWaylandOutput*)data;
  64. PMONITOR->initialized = true;
  65. }
  66. static void scale(void* data, wl_output* wl_output, int32_t scale) {
  67. const auto PMONITOR = (SWaylandOutput*)data;
  68. PMONITOR->scale = scale;
  69. if (PMONITOR->layerSurface.get())
  70. PMONITOR->driver->resizeLSSurfaceEGL(PMONITOR->layerSurface.get());
  71. if (PMONITOR->initialized)
  72. PMONITOR->driver->wallpaperApplication->getOutput()->reset();
  73. }
  74. static void name(void* data, wl_output* wl_output, const char* name) {
  75. const auto PMONITOR = (SWaylandOutput*)data;
  76. if (name)
  77. PMONITOR->name = name;
  78. }
  79. static void description(void* data, wl_output* wl_output, const char* description) {
  80. // ignored
  81. }
  82. const wl_output_listener outputListener = {.geometry = geometry, .mode = mode, .done = done, .scale = scale, .name = name, .description = description};
  83. static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
  84. const auto PDRIVER = (CWaylandOpenGLDriver*)data;
  85. if (strcmp(interface, wl_compositor_interface.name) == 0) {
  86. PDRIVER->waylandContext.compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 4);
  87. } else if (strcmp(interface, wl_shm_interface.name) == 0) {
  88. PDRIVER->waylandContext.shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1);
  89. } else if (strcmp(interface, wl_output_interface.name) == 0) {
  90. const auto POUTPUT = PDRIVER->m_outputs.emplace_back(std::make_unique<SWaylandOutput>()).get();
  91. POUTPUT->output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 4);
  92. POUTPUT->name = "";
  93. POUTPUT->size = {0, 0};
  94. POUTPUT->waylandName = name;
  95. POUTPUT->driver = PDRIVER;
  96. wl_output_add_listener(POUTPUT->output, &outputListener, POUTPUT);
  97. } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
  98. PDRIVER->waylandContext.layerShell = (zwlr_layer_shell_v1*)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
  99. } else if (strcmp(interface, wl_seat_interface.name) == 0) {
  100. PDRIVER->waylandContext.seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1);
  101. wl_seat_add_listener(PDRIVER->waylandContext.seat, &seatListener, PDRIVER);
  102. }
  103. }
  104. static void handleGlobalRemoved(void *data, struct wl_registry *registry, uint32_t id) {
  105. // todo: outputs
  106. }
  107. const struct wl_registry_listener registryListener = {
  108. .global = handleGlobal,
  109. .global_remove = handleGlobalRemoved,
  110. };
  111. void CWaylandOpenGLDriver::initEGL() {
  112. const char* CLIENT_EXTENSIONS = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  113. if (!CLIENT_EXTENSIONS)
  114. sLog.exception("Failed to query EGL Extensions");
  115. const std::string CLIENTEXTENSIONS = std::string(CLIENT_EXTENSIONS);
  116. if (CLIENTEXTENSIONS.find("EGL_EXT_platform_base") == std::string::npos)
  117. sLog.exception("EGL_EXT_platform_base not supported by EGL!");
  118. if (CLIENTEXTENSIONS.find("EGL_EXT_platform_wayland") == std::string::npos)
  119. sLog.exception("EGL_EXT_platform_wayland not supported by EGL!");
  120. PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
  121. eglContext.eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
  122. if (!eglGetPlatformDisplayEXT || !eglContext.eglCreatePlatformWindowSurfaceEXT)
  123. sLog.exception("EGL did not return EXT proc pointers!");
  124. auto deinitEGL = [&] () -> void {
  125. eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  126. if (eglContext.display)
  127. eglTerminate(eglContext.display);
  128. eglReleaseThread();
  129. };
  130. eglContext.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, waylandContext.display, nullptr);
  131. if (eglContext.display == EGL_NO_DISPLAY) {
  132. deinitEGL();
  133. sLog.exception("eglGetPlatformDisplayEXT failed!");
  134. }
  135. if (!eglInitialize(eglContext.display, nullptr, nullptr)) {
  136. deinitEGL();
  137. sLog.exception("eglInitialize failed!");
  138. }
  139. const std::string CLIENTEXTENSIONSPOSTINIT = std::string(eglQueryString(eglContext.display, EGL_EXTENSIONS));
  140. if (CLIENTEXTENSIONSPOSTINIT.find("EGL_KHR_create_context") == std::string::npos) {
  141. deinitEGL();
  142. sLog.exception("EGL_KHR_create_context not supported!");
  143. }
  144. EGLint matchedConfigs = 0;
  145. const EGLint CONFIG_ATTRIBUTES[] = {
  146. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  147. EGL_RED_SIZE, 1,
  148. EGL_GREEN_SIZE, 1,
  149. EGL_BLUE_SIZE, 1,
  150. EGL_SAMPLES, 4,
  151. EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
  152. EGL_NONE,
  153. };
  154. if (!eglChooseConfig(eglContext.display, CONFIG_ATTRIBUTES, &eglContext.config, 1, &matchedConfigs)) {
  155. deinitEGL();
  156. sLog.exception("eglChooseConfig failed!");
  157. }
  158. if (matchedConfigs == 0) {
  159. deinitEGL();
  160. sLog.exception("eglChooseConfig failed! (matched 0 configs)");
  161. }
  162. if (!eglBindAPI(EGL_OPENGL_API)) {
  163. deinitEGL();
  164. sLog.exception("eglBindAPI failed!");
  165. }
  166. const EGLint CONTEXT_ATTRIBUTES[] = {
  167. EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
  168. EGL_CONTEXT_MINOR_VERSION_KHR, 3,
  169. EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
  170. EGL_NONE,
  171. };
  172. eglContext.context = eglCreateContext(eglContext.display, eglContext.config, EGL_NO_CONTEXT, CONTEXT_ATTRIBUTES);
  173. if (eglContext.context == EGL_NO_CONTEXT) {
  174. sLog.error("eglCreateContext error " + std::to_string(eglGetError()));
  175. deinitEGL();
  176. sLog.exception("eglCreateContext failed!");
  177. }
  178. }
  179. void CWaylandOpenGLDriver::finishEGL() {
  180. eglMakeCurrent(eglContext.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  181. eglDestroyContext(eglContext.display, eglContext.context);
  182. eglTerminate(eglContext.display);
  183. eglReleaseThread();
  184. }
  185. static void handleLSConfigure(void *data, zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h) {
  186. const auto PLS = (CLayerSurface*)data;
  187. PLS->size = {w, h};
  188. PLS->output->driver->resizeLSSurfaceEGL(PLS);
  189. zwlr_layer_surface_v1_ack_configure(surface, serial);
  190. }
  191. static void handleLSClosed(void *data, zwlr_layer_surface_v1 *surface) {
  192. const auto PLS = (CLayerSurface*)data;
  193. PLS->output->driver->onLayerClose(PLS);
  194. }
  195. void CWaylandOpenGLDriver::onLayerClose(CLayerSurface* layerSurface) {
  196. eglDestroySurface(eglContext.display, layerSurface->eglSurface);
  197. wl_egl_window_destroy(layerSurface->eglWindow);
  198. zwlr_layer_surface_v1_destroy(layerSurface->layerSurface);
  199. wl_surface_destroy(layerSurface->surface);
  200. sLog.exception("Compositor closed our LS!"); // todo: handle this?
  201. }
  202. const struct zwlr_layer_surface_v1_listener layerSurfaceListener = {
  203. .configure = handleLSConfigure,
  204. .closed = handleLSClosed,
  205. };
  206. static void surfaceFrameCallback(void *data, struct wl_callback *cb, uint32_t time) {
  207. const auto PLS = (CLayerSurface*)data;
  208. wl_callback_destroy(cb);
  209. PLS->frameCallback = nullptr;
  210. PLS->output->rendering = true;
  211. PLS->output->driver->wallpaperApplication->renderFrame();
  212. PLS->output->rendering = false;
  213. float renderTime = PLS->output->driver->getRenderTime();
  214. if ((renderTime - PLS->lastTime) < PLS->minimumTime)
  215. usleep ((PLS->minimumTime - (renderTime - PLS->lastTime)) * CLOCKS_PER_SEC);
  216. PLS->lastTime = renderTime;
  217. }
  218. const struct wl_callback_listener frameListener = {
  219. .done = surfaceFrameCallback
  220. };
  221. CLayerSurface::CLayerSurface(CWaylandOpenGLDriver* pDriver, SWaylandOutput* pOutput) {
  222. surface = wl_compositor_create_surface(pDriver->waylandContext.compositor);
  223. layerSurface = zwlr_layer_shell_v1_get_layer_surface(pDriver->waylandContext.layerShell, surface, pOutput->output, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "linux-wallpaperengine");
  224. output = pOutput;
  225. if (!layerSurface)
  226. sLog.exception("Failed to get a layer surface");
  227. wl_region* region = wl_compositor_create_region(pDriver->waylandContext.compositor);
  228. wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
  229. zwlr_layer_surface_v1_set_size(layerSurface, 0, 0);
  230. zwlr_layer_surface_v1_set_anchor(layerSurface, ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM);
  231. zwlr_layer_surface_v1_set_keyboard_interactivity(layerSurface, false);
  232. zwlr_layer_surface_v1_add_listener(layerSurface, &layerSurfaceListener, this);
  233. zwlr_layer_surface_v1_set_exclusive_zone(layerSurface, -1);
  234. wl_surface_set_input_region(surface, region);
  235. wl_surface_commit(surface);
  236. wl_display_roundtrip(pDriver->waylandContext.display);
  237. eglWindow = wl_egl_window_create(surface, size.x * output->scale, size.y * output->scale);
  238. eglSurface = pDriver->eglContext.eglCreatePlatformWindowSurfaceEXT(pDriver->eglContext.display, pDriver->eglContext.config, eglWindow, nullptr);
  239. output->lsSize = size;
  240. wl_surface_commit(surface);
  241. wl_display_roundtrip(pDriver->waylandContext.display);
  242. wl_display_flush(pDriver->waylandContext.display);
  243. static const auto XCURSORSIZE = getenv("XCURSOR_SIZE") ? std::stoi(getenv("XCURSOR_SIZE")) : 24;
  244. const auto PRCURSORTHEME = wl_cursor_theme_load(getenv("XCURSOR_THEME"), XCURSORSIZE * output->scale, pDriver->waylandContext.shm);
  245. if (!PRCURSORTHEME)
  246. sLog.exception("Failed to get a cursor theme");
  247. pointer = wl_cursor_theme_get_cursor(PRCURSORTHEME, "left_ptr");
  248. cursorSurface = wl_compositor_create_surface(pDriver->waylandContext.compositor);
  249. if (!cursorSurface)
  250. sLog.exception("Failed to get a cursor surface");
  251. if (eglMakeCurrent(pDriver->eglContext.display, eglSurface, eglSurface, pDriver->eglContext.context) == EGL_FALSE)
  252. sLog.exception("Failed to make egl current");
  253. minimumTime = 1.0f / pDriver->wallpaperApplication->getContext().settings.render.maximumFPS;
  254. }
  255. CLayerSurface::~CLayerSurface() {
  256. ;
  257. }
  258. CWaylandOpenGLDriver::CWaylandOpenGLDriver(const char* windowTitle, CApplicationContext& context, CWallpaperApplication* app) : m_frameCounter(0) {
  259. wallpaperApplication = app;
  260. waylandContext.display = wl_display_connect(NULL);
  261. if (!waylandContext.display)
  262. sLog.exception("Failed to query wayland display");
  263. waylandContext.registry = wl_display_get_registry(waylandContext.display);
  264. wl_registry_add_listener(waylandContext.registry, &registryListener, this);
  265. wl_display_dispatch(waylandContext.display);
  266. wl_display_roundtrip(waylandContext.display);
  267. if (!waylandContext.compositor || !waylandContext.shm || !waylandContext.layerShell || m_outputs.empty())
  268. sLog.exception("Failed to bind to required interfaces");
  269. initEGL();
  270. bool any = false;
  271. for (auto& o : m_outputs) {
  272. if (std::find_if(context.settings.general.screenBackgrounds.begin(), context.settings.general.screenBackgrounds.end(), [&] (const auto& e) { return e.first == o->name; }) != context.settings.general.screenBackgrounds.end()) {
  273. o->layerSurface = std::make_unique<CLayerSurface>(this, o.get());
  274. any = true;
  275. }
  276. }
  277. if (!any && std::find_if(context.settings.general.screenBackgrounds.begin(), context.settings.general.screenBackgrounds.end(), [&] (const auto& e) { return e.first == "auto"; }) != context.settings.general.screenBackgrounds.end()) {
  278. m_outputs[0]->layerSurface = std::make_unique<CLayerSurface>(this, m_outputs[0].get());
  279. any = true;
  280. }
  281. if (!any)
  282. sLog.exception("No outputs could be initialized!");
  283. GLenum result = glewInit ();
  284. if (result != GLEW_OK)
  285. sLog.error("Failed to initialize GLEW: ", glewGetErrorString (result));
  286. FreeImage_Initialise (TRUE);
  287. }
  288. CWaylandOpenGLDriver::~CWaylandOpenGLDriver() {
  289. ;
  290. }
  291. void CWaylandOpenGLDriver::dispatchEventQueue() const {
  292. wl_display_dispatch(waylandContext.display);
  293. }
  294. void* CWaylandOpenGLDriver::getWindowHandle () const {
  295. return nullptr;
  296. }
  297. float CWaylandOpenGLDriver::getRenderTime () const {
  298. return (float)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000000.0;
  299. }
  300. bool CWaylandOpenGLDriver::closeRequested () {
  301. return false;
  302. }
  303. void CWaylandOpenGLDriver::resizeWindow (glm::ivec2 size) {
  304. ;
  305. }
  306. void CWaylandOpenGLDriver::resizeWindow (glm::ivec4 sizeandpos) {
  307. ;
  308. }
  309. void CWaylandOpenGLDriver::showWindow () {
  310. ;
  311. }
  312. void CWaylandOpenGLDriver::hideWindow () {
  313. ;
  314. }
  315. glm::ivec2 CWaylandOpenGLDriver::getFramebufferSize () const {
  316. return glm::ivec2{0, 0};
  317. }
  318. void CWaylandOpenGLDriver::swapBuffers () {
  319. ;
  320. }
  321. void CWaylandOpenGLDriver::resizeLSSurfaceEGL(CLayerSurface* layerSurface) {
  322. if (layerSurface->eglWindow) {
  323. layerSurface->output->lsSize = layerSurface->size;
  324. wl_egl_window_resize(layerSurface->eglWindow, layerSurface->size.x * layerSurface->output->scale, layerSurface->size.y * layerSurface->output->scale, 0, 0);
  325. if (layerSurface->frameCallback) {
  326. wl_callback_destroy(layerSurface->frameCallback);
  327. layerSurface->frameCallback = nullptr;
  328. }
  329. wallpaperApplication->getOutput()->reset();
  330. layerSurface->output->rendering = true;
  331. wallpaperApplication->renderFrame();
  332. layerSurface->output->rendering = false;
  333. }
  334. }
  335. uint32_t CWaylandOpenGLDriver::getFrameCounter () const {
  336. return m_frameCounter;
  337. }
  338. GLFWwindow* CWaylandOpenGLDriver::getWindow () {
  339. return nullptr;
  340. }
  341. #include <iostream>
  342. void CWaylandOpenGLDriver::makeCurrent(const std::string& outputName) const {
  343. for (auto& o : m_outputs) {
  344. if (o->name != outputName)
  345. continue;
  346. if (eglMakeCurrent(eglContext.display, o->layerSurface->eglSurface, o->layerSurface->eglSurface, eglContext.context) == EGL_FALSE) {
  347. std::cerr << "Couldn't make egl current";
  348. }
  349. }
  350. }
  351. CLayerSurface* CWaylandOpenGLDriver::surfaceToLS(wl_surface* surface) {
  352. for (auto& o : m_outputs) {
  353. if (o->layerSurface->surface == surface)
  354. return o->layerSurface.get();
  355. }
  356. return nullptr;
  357. }
  358. bool CWaylandOpenGLDriver::shouldRenderOutput(const std::string& outputName) const {
  359. for (auto& o : m_outputs) {
  360. if (o->name == outputName)
  361. return o->layerSurface.get() && (o->rendering || !o->layerSurface->callbackInitialized);
  362. }
  363. return false;
  364. }
  365. bool CWaylandOpenGLDriver::requiresSeparateFlips() const {
  366. return true;
  367. }
  368. void CWaylandOpenGLDriver::swapOutputBuffer(const std::string& outputName) {
  369. for (auto& o : m_outputs) {
  370. if (o->name != outputName)
  371. continue;
  372. o->layerSurface->callbackInitialized = true;
  373. eglMakeCurrent(eglContext.display, o->layerSurface->eglSurface, o->layerSurface->eglSurface, eglContext.context);
  374. o->layerSurface->frameCallback = wl_surface_frame(o->layerSurface->surface);
  375. wl_callback_add_listener(o->layerSurface->frameCallback, &frameListener, o->layerSurface.get());
  376. eglSwapBuffers(eglContext.display, o->layerSurface->eglSurface);
  377. wl_surface_set_buffer_scale(o->layerSurface->surface, o->scale);
  378. wl_surface_damage_buffer(o->layerSurface->surface, 0, 0, INT32_MAX, INT32_MAX);
  379. wl_surface_commit(o->layerSurface->surface);
  380. m_frameCounter++;
  381. }
  382. }