GLFWOpenGLDriver.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #include "GLFWOpenGLDriver.h"
  2. #include "VideoFactories.h"
  3. #include "WallpaperEngine/Logging/Log.h"
  4. #include "WallpaperEngine/Render/Drivers/Output/GLFWWindowOutput.h"
  5. #ifdef ENABLE_X11
  6. #include "WallpaperEngine/Render/Drivers/Output/X11Output.h"
  7. #endif
  8. #define GLFW_EXPOSE_NATIVE_X11
  9. #include "WallpaperEngine/Debugging/CallStack.h"
  10. #include <GLFW/glfw3native.h>
  11. #include <unistd.h>
  12. using namespace WallpaperEngine::Render::Drivers;
  13. void CustomGLFWErrorHandler (int errorCode, const char* reason) { sLog.error ("GLFW error ", errorCode, ": ", reason); }
  14. GLFWOpenGLDriver::GLFWOpenGLDriver (const char* windowTitle, ApplicationContext& context, WallpaperApplication& app) :
  15. VideoDriver (app, m_mouseInput), m_context (context), m_mouseInput (*this) {
  16. glfwSetErrorCallback (CustomGLFWErrorHandler);
  17. // initialize glfw
  18. if (glfwInit () == GLFW_FALSE) {
  19. sLog.exception ("Failed to initialize glfw");
  20. }
  21. // set some window hints (opengl version to be used)
  22. glfwWindowHint (GLFW_SAMPLES, 4);
  23. glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
  24. glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3);
  25. glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  26. glfwWindowHint (GLFW_VISIBLE, GLFW_FALSE);
  27. // set X11-specific hints
  28. glfwWindowHintString (GLFW_X11_CLASS_NAME, "linux-wallpaperengine");
  29. glfwWindowHintString (GLFW_X11_INSTANCE_NAME, "linux-wallpaperengine");
  30. // for forced window mode, we can set some hints that'll help position the window
  31. if (context.settings.render.mode == Application::ApplicationContext::EXPLICIT_WINDOW) {
  32. glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE);
  33. glfwWindowHint (GLFW_DECORATED, GLFW_FALSE);
  34. glfwWindowHint (GLFW_FLOATING, GLFW_TRUE);
  35. }
  36. #if !NDEBUG
  37. glfwWindowHint (GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
  38. #endif /* DEBUG */
  39. // create window, size doesn't matter as long as we don't show it
  40. this->m_window = glfwCreateWindow (640, 480, windowTitle, nullptr, nullptr);
  41. if (this->m_window == nullptr) {
  42. sLog.exception ("Cannot create window");
  43. }
  44. // make context current, required for glew initialization
  45. glfwMakeContextCurrent (this->m_window);
  46. // initialize glew for rendering
  47. if (const GLenum result = glewInit (); result != GLEW_OK) {
  48. sLog.error ("Failed to initialize GLEW: ", glewGetErrorString (result));
  49. }
  50. // setup output
  51. if (context.settings.render.mode == ApplicationContext::EXPLICIT_WINDOW
  52. || context.settings.render.mode == ApplicationContext::NORMAL_WINDOW) {
  53. m_output = new WallpaperEngine::Render::Drivers::Output::GLFWWindowOutput (context, *this);
  54. }
  55. #ifdef ENABLE_X11
  56. else {
  57. m_output = new WallpaperEngine::Render::Drivers::Output::X11Output (context, *this);
  58. }
  59. #else
  60. else {
  61. sLog.exception ("Trying to start GLFW in background mode without X11 support installed. Bailing out");
  62. }
  63. #endif
  64. }
  65. GLFWOpenGLDriver::~GLFWOpenGLDriver () { glfwTerminate (); }
  66. Output::Output& GLFWOpenGLDriver::getOutput () { return *this->m_output; }
  67. float GLFWOpenGLDriver::getRenderTime () const { return static_cast<float> (glfwGetTime ()); }
  68. bool GLFWOpenGLDriver::closeRequested () { return glfwWindowShouldClose (this->m_window); }
  69. void GLFWOpenGLDriver::resizeWindow (glm::ivec2 size) { glfwSetWindowSize (this->m_window, size.x, size.y); }
  70. void GLFWOpenGLDriver::resizeWindow (glm::ivec4 sizeandpos) {
  71. glfwSetWindowPos (this->m_window, sizeandpos.x, sizeandpos.y);
  72. glfwSetWindowSize (this->m_window, sizeandpos.z, sizeandpos.w);
  73. }
  74. void GLFWOpenGLDriver::showWindow () { glfwShowWindow (this->m_window); }
  75. void GLFWOpenGLDriver::hideWindow () { glfwHideWindow (this->m_window); }
  76. glm::ivec2 GLFWOpenGLDriver::getFramebufferSize () const {
  77. glm::ivec2 size;
  78. glfwGetFramebufferSize (this->m_window, &size.x, &size.y);
  79. return size;
  80. }
  81. uint32_t GLFWOpenGLDriver::getFrameCounter () const { return this->m_frameCounter; }
  82. void GLFWOpenGLDriver::dispatchEventQueue () {
  83. static float startTime, endTime, minimumTime = 1.0f / this->m_context.settings.render.maximumFPS;
  84. // get the start time of the frame
  85. startTime = this->getRenderTime ();
  86. // clear the screen
  87. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  88. for (const auto& [screen, viewport] : this->m_output->getViewports ()) {
  89. this->getApp ().update (viewport);
  90. }
  91. // read the full texture into the image
  92. if (this->m_output->haveImageBuffer ()) {
  93. // 4.5 supports glReadnPixels, anything older doesn't...
  94. if (GLEW_VERSION_4_5) {
  95. glReadnPixels (
  96. 0, 0, this->m_output->getFullWidth (), this->m_output->getFullHeight (), GL_BGRA, GL_UNSIGNED_BYTE,
  97. this->m_output->getImageBufferSize (), this->m_output->getImageBuffer ()
  98. );
  99. } else {
  100. // fallback to old version
  101. glReadPixels (
  102. 0, 0, this->m_output->getFullWidth (), this->m_output->getFullHeight (), GL_BGRA, GL_UNSIGNED_BYTE,
  103. this->m_output->getImageBuffer ()
  104. );
  105. }
  106. GLenum error = glGetError ();
  107. if (error != GL_NO_ERROR) {
  108. sLog.exception ("OpenGL error when reading texture ", error);
  109. }
  110. }
  111. // TODO: FRAMETIME CONTROL SHOULD GO BACK TO THE CWALLPAPAERAPPLICATION ONCE ACTUAL PARTICLES ARE IMPLEMENTED
  112. // TODO: AS THOSE, MORE THAN LIKELY, WILL REQUIRE OF A DIFFERENT PROCESSING RATE
  113. // update the output with the given image
  114. this->m_output->updateRender ();
  115. // do buffer swapping first
  116. glfwSwapBuffers (this->m_window);
  117. // poll for events
  118. glfwPollEvents ();
  119. // increase frame counter
  120. this->m_frameCounter++;
  121. // get the end time of the frame
  122. endTime = this->getRenderTime ();
  123. // ensure the frame time is correct to not overrun FPS
  124. if ((endTime - startTime) < minimumTime) {
  125. usleep ((minimumTime - (endTime - startTime)) * CLOCKS_PER_SEC);
  126. }
  127. }
  128. void* GLFWOpenGLDriver::getProcAddress (const char* name) const {
  129. return reinterpret_cast<void*> (glfwGetProcAddress (name));
  130. }
  131. GLFWwindow* GLFWOpenGLDriver::getWindow () const { return this->m_window; }
  132. __attribute__ ((constructor)) void registerGLFWOpenGLDriver () {
  133. sVideoFactories.registerDriver (
  134. ApplicationContext::DESKTOP_BACKGROUND, "x11",
  135. [] (ApplicationContext& context, WallpaperApplication& application) -> std::unique_ptr<VideoDriver> {
  136. return std::make_unique<GLFWOpenGLDriver> ("wallpaperengine", context, application);
  137. }
  138. );
  139. sVideoFactories.registerDriver (
  140. ApplicationContext::EXPLICIT_WINDOW, DEFAULT_WINDOW_NAME,
  141. [] (ApplicationContext& context, WallpaperApplication& application) -> std::unique_ptr<VideoDriver> {
  142. return std::make_unique<GLFWOpenGLDriver> ("wallpaperengine", context, application);
  143. }
  144. );
  145. sVideoFactories.registerDriver (
  146. ApplicationContext::NORMAL_WINDOW, DEFAULT_WINDOW_NAME,
  147. [] (ApplicationContext& context, WallpaperApplication& application) -> std::unique_ptr<VideoDriver> {
  148. return std::make_unique<GLFWOpenGLDriver> ("wallpaperengine", context, application);
  149. }
  150. );
  151. }