CWaylandOpenGLDriver.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 (
  18. void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface,
  19. wl_fixed_t surface_x, wl_fixed_t surface_y)
  20. {
  21. const auto driver = static_cast <CWaylandOpenGLDriver*> (data);
  22. const auto viewport = driver->surfaceToViewport (surface);
  23. driver->viewportInFocus = viewport;
  24. wl_surface_set_buffer_scale(viewport->cursorSurface, viewport->scale);
  25. wl_surface_attach(viewport->cursorSurface, wl_cursor_image_get_buffer(viewport->pointer->images[0]), 0, 0);
  26. wl_pointer_set_cursor(wl_pointer, serial, viewport->cursorSurface, viewport->pointer->images[0]->hotspot_x, viewport->pointer->images[0]->hotspot_y);
  27. wl_surface_commit(viewport->cursorSurface);
  28. }
  29. static void handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface)
  30. {
  31. }
  32. static void handlePointerAxis(void* data, wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
  33. {
  34. }
  35. static void handlePointerMotion(
  36. void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
  37. {
  38. const auto driver = static_cast <CWaylandOpenGLDriver*> (data);
  39. auto x = wl_fixed_to_double(surface_x);
  40. auto y = wl_fixed_to_double(surface_y);
  41. if (!driver->viewportInFocus)
  42. return;
  43. driver->viewportInFocus->mousePos = {x * driver->viewportInFocus->scale, y * driver->viewportInFocus->scale};
  44. }
  45. static void handlePointerButton(
  46. void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state)
  47. {
  48. }
  49. const struct wl_pointer_listener pointerListener =
  50. {
  51. .enter = handlePointerEnter,
  52. .leave = handlePointerLeave,
  53. .motion = handlePointerMotion,
  54. .button = handlePointerButton,
  55. .axis = handlePointerAxis
  56. };
  57. static void handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities)
  58. {
  59. if (capabilities & WL_SEAT_CAPABILITY_POINTER)
  60. wl_pointer_add_listener(wl_seat_get_pointer(wl_seat), &pointerListener, data);
  61. }
  62. const struct wl_seat_listener seatListener =
  63. {
  64. .capabilities = handleCapabilities
  65. };
  66. static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
  67. {
  68. const auto driver = static_cast <CWaylandOpenGLDriver*> (data);
  69. if (strcmp(interface, wl_compositor_interface.name) == 0) {
  70. driver->getWaylandContext()->compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 4);
  71. } else if (strcmp(interface, wl_shm_interface.name) == 0) {
  72. driver->getWaylandContext()->shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1);
  73. } else if (strcmp(interface, wl_output_interface.name) == 0) {
  74. driver->m_screens.emplace_back (new WallpaperEngine::Render::Drivers::Output::CWaylandOutputViewport (driver, name, registry));
  75. } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
  76. driver->getWaylandContext()->layerShell = (zwlr_layer_shell_v1*)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
  77. } else if (strcmp(interface, wl_seat_interface.name) == 0) {
  78. driver->getWaylandContext()->seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1);
  79. wl_seat_add_listener(driver->getWaylandContext()->seat, &seatListener, driver);
  80. }
  81. }
  82. static void handleGlobalRemoved(void *data, struct wl_registry *registry, uint32_t id)
  83. {
  84. // todo: outputs
  85. }
  86. const struct wl_registry_listener registryListener =
  87. {
  88. .global = handleGlobal,
  89. .global_remove = handleGlobalRemoved,
  90. };
  91. void CWaylandOpenGLDriver::initEGL()
  92. {
  93. const char* CLIENT_EXTENSIONS = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  94. if (!CLIENT_EXTENSIONS)
  95. sLog.exception("Failed to query EGL Extensions");
  96. const std::string CLIENTEXTENSIONS = std::string(CLIENT_EXTENSIONS);
  97. if (CLIENTEXTENSIONS.find("EGL_EXT_platform_base") == std::string::npos)
  98. sLog.exception("EGL_EXT_platform_base not supported by EGL!");
  99. if (CLIENTEXTENSIONS.find("EGL_EXT_platform_wayland") == std::string::npos)
  100. sLog.exception("EGL_EXT_platform_wayland not supported by EGL!");
  101. PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
  102. m_eglContext.eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
  103. if (!eglGetPlatformDisplayEXT || !m_eglContext.eglCreatePlatformWindowSurfaceEXT)
  104. sLog.exception("EGL did not return EXT proc pointers!");
  105. m_eglContext.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_waylandContext.display, nullptr);
  106. if (m_eglContext.display == EGL_NO_DISPLAY)
  107. sLog.exception("eglGetPlatformDisplayEXT failed!");
  108. if (!eglInitialize(m_eglContext.display, nullptr, nullptr))
  109. sLog.exception("eglInitialize failed!");
  110. const std::string CLIENTEXTENSIONSPOSTINIT = std::string(eglQueryString(m_eglContext.display, EGL_EXTENSIONS));
  111. if (CLIENTEXTENSIONSPOSTINIT.find("EGL_KHR_create_context") == std::string::npos)
  112. sLog.exception("EGL_KHR_create_context not supported!");
  113. EGLint matchedConfigs = 0;
  114. const EGLint CONFIG_ATTRIBUTES[] = {
  115. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  116. EGL_RED_SIZE, 1,
  117. EGL_GREEN_SIZE, 1,
  118. EGL_BLUE_SIZE, 1,
  119. EGL_SAMPLES, 4,
  120. EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
  121. EGL_NONE,
  122. };
  123. if (!eglChooseConfig(m_eglContext.display, CONFIG_ATTRIBUTES, &m_eglContext.config, 1, &matchedConfigs))
  124. sLog.exception("eglChooseConfig failed!");
  125. if (matchedConfigs == 0)
  126. sLog.exception("eglChooseConfig failed! (matched 0 configs)");
  127. if (!eglBindAPI(EGL_OPENGL_API))
  128. sLog.exception("eglBindAPI failed!");
  129. const EGLint CONTEXT_ATTRIBUTES[] = {
  130. EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
  131. EGL_CONTEXT_MINOR_VERSION_KHR, 3,
  132. EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
  133. EGL_NONE,
  134. };
  135. m_eglContext.context = eglCreateContext(m_eglContext.display, m_eglContext.config, EGL_NO_CONTEXT, CONTEXT_ATTRIBUTES);
  136. if (m_eglContext.context == EGL_NO_CONTEXT) {
  137. sLog.error("eglCreateContext error " + std::to_string(eglGetError()));
  138. sLog.exception("eglCreateContext failed!");
  139. }
  140. }
  141. void CWaylandOpenGLDriver::onLayerClose(Output::CWaylandOutputViewport* viewport)
  142. {
  143. sLog.error ("Compositor closed our LS, freeing data...");
  144. if (viewport->eglSurface)
  145. eglDestroySurface (m_eglContext.display, viewport->eglSurface);
  146. if (viewport->eglWindow)
  147. wl_egl_window_destroy(viewport->eglWindow);
  148. if (viewport->layerSurface)
  149. zwlr_layer_surface_v1_destroy(viewport->layerSurface);
  150. if (viewport->surface)
  151. wl_surface_destroy(viewport->surface);
  152. // remove the output from the list
  153. std::remove (this->m_screens.begin (), this->m_screens.end (), viewport);
  154. // reset the viewports
  155. this->getOutput ().reset ();
  156. // finally free memory used by the viewport
  157. delete viewport;
  158. }
  159. CWaylandOpenGLDriver::CWaylandOpenGLDriver(CApplicationContext& context, CWallpaperApplication& app) :
  160. m_frameCounter(0),
  161. m_fullscreenDetector (context, *this),
  162. m_output (context, *this),
  163. m_requestedExit (false),
  164. CVideoDriver (app)
  165. {
  166. m_waylandContext.display = wl_display_connect (nullptr);
  167. if (!m_waylandContext.display)
  168. sLog.exception ("Failed to query wayland display");
  169. m_waylandContext.registry = wl_display_get_registry(m_waylandContext.display);
  170. wl_registry_add_listener(m_waylandContext.registry, &registryListener, this);
  171. wl_display_dispatch(m_waylandContext.display);
  172. wl_display_roundtrip(m_waylandContext.display);
  173. if (!m_waylandContext.compositor || !m_waylandContext.shm || !m_waylandContext.layerShell || this->m_screens.empty())
  174. sLog.exception ("Failed to bind to required interfaces");
  175. initEGL();
  176. bool any = false;
  177. for (auto& o : this->m_screens)
  178. {
  179. const auto cur = context.settings.general.screenBackgrounds.find (o->name);
  180. if (cur == context.settings.general.screenBackgrounds.end ())
  181. continue;
  182. o->setupLS ();
  183. any = true;
  184. }
  185. if (!any)
  186. sLog.exception("No outputs could be initialized, please check the parameters and try again");
  187. GLenum result = glewInit ();
  188. if (result != GLEW_OK)
  189. sLog.error("Failed to initialize GLEW: ", glewGetErrorString (result));
  190. FreeImage_Initialise (TRUE);
  191. }
  192. CWaylandOpenGLDriver::~CWaylandOpenGLDriver ()
  193. {
  194. eglMakeCurrent (EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  195. if (m_eglContext.context != EGL_NO_CONTEXT)
  196. eglDestroyContext (m_eglContext.display, m_eglContext.context);
  197. eglTerminate (m_eglContext.display);
  198. eglReleaseThread ();
  199. // disconnect from wayland display
  200. if (this->m_waylandContext.display)
  201. wl_display_disconnect (this->m_waylandContext.display);
  202. }
  203. void CWaylandOpenGLDriver::dispatchEventQueue()
  204. {
  205. static bool initialized = false;
  206. if (!initialized)
  207. {
  208. initialized = true;
  209. for (const auto& viewport : this->getOutput ().getViewports ())
  210. this->getApp ().update (viewport.second);
  211. }
  212. if (wl_display_dispatch(m_waylandContext.display) == -1)
  213. m_requestedExit = true;
  214. m_frameCounter ++;
  215. }
  216. Detectors::CFullScreenDetector& CWaylandOpenGLDriver::getFullscreenDetector ()
  217. {
  218. return this->m_fullscreenDetector;
  219. }
  220. Output::COutput& CWaylandOpenGLDriver::getOutput ()
  221. {
  222. return this->m_output;
  223. }
  224. float CWaylandOpenGLDriver::getRenderTime () const
  225. {
  226. return (float)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000000.0;
  227. }
  228. bool CWaylandOpenGLDriver::closeRequested ()
  229. {
  230. return this->m_requestedExit;
  231. }
  232. void CWaylandOpenGLDriver::resizeWindow (glm::ivec2 size)
  233. {
  234. }
  235. void CWaylandOpenGLDriver::resizeWindow (glm::ivec4 sizeandpos)
  236. {
  237. }
  238. void CWaylandOpenGLDriver::showWindow ()
  239. {
  240. }
  241. void CWaylandOpenGLDriver::hideWindow ()
  242. {
  243. }
  244. glm::ivec2 CWaylandOpenGLDriver::getFramebufferSize () const
  245. {
  246. return glm::ivec2{0, 0};
  247. }
  248. uint32_t CWaylandOpenGLDriver::getFrameCounter () const
  249. {
  250. return m_frameCounter;
  251. }
  252. CWaylandOpenGLDriver::SEGLContext* CWaylandOpenGLDriver::getEGLContext ()
  253. {
  254. return &this->m_eglContext;
  255. }
  256. void* CWaylandOpenGLDriver::getProcAddress (const char* name) const
  257. {
  258. return reinterpret_cast <void*> (eglGetProcAddress (name));
  259. }
  260. CWaylandOpenGLDriver::SWaylandContext* CWaylandOpenGLDriver::getWaylandContext ()
  261. {
  262. return &this->m_waylandContext;
  263. }
  264. Output::CWaylandOutputViewport* CWaylandOpenGLDriver::surfaceToViewport(wl_surface* surface)
  265. {
  266. for (auto& o : m_screens)
  267. {
  268. if (o->surface == surface)
  269. return o;
  270. }
  271. return nullptr;
  272. }