linux-wallpaperengine/src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.cpp
Alexis Maiquez 723fca552c Wayland: Moved frame-time checking to CWaylandOpenGLDriver instead of viewports
Wayland doesn't require specifics timings, each frame drawn re-queues a new frame
  so treating it as "render the screens" seems to be a safe bet for now
  As indicated in the TODOs once actual work is being done in the event loop
  it should be replaced by a non-blocking option in case no surface is being rendered

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
2023-05-06 14:14:21 +02:00

188 lines
5.4 KiB
C++

#include "CX11OpenGLDriver.h"
#include "common.h"
#include "WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h"
#include <FreeImage.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
#include <unistd.h>
using namespace WallpaperEngine::Render::Drivers;
void CustomGLFWErrorHandler (int errorCode, const char* reason)
{
sLog.error ("GLFW error ", errorCode, ": ", reason);
}
CX11OpenGLDriver::CX11OpenGLDriver (const char* windowTitle, CApplicationContext& context, CWallpaperApplication& app) :
m_frameCounter (0),
m_fullscreenDetector (context, *this),
m_context (context),
CVideoDriver (app)
{
glfwSetErrorCallback (CustomGLFWErrorHandler);
// initialize glfw
if (glfwInit () == GLFW_FALSE)
sLog.exception ("Failed to initialize glfw");
// set some window hints (opengl version to be used)
glfwWindowHint (GLFW_SAMPLES, 4);
glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint (GLFW_VISIBLE, GLFW_FALSE);
// set X11-specific hints
glfwWindowHintString (GLFW_X11_CLASS_NAME, "linux-wallpaperengine");
glfwWindowHintString (GLFW_X11_INSTANCE_NAME, "linux-wallpaperengine");
// for forced window mode, we can set some hints that'll help position the window
if (context.settings.render.mode == Application::CApplicationContext::EXPLICIT_WINDOW)
{
glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint (GLFW_DECORATED, GLFW_FALSE);
glfwWindowHint (GLFW_FLOATING, GLFW_TRUE);
}
#if !NDEBUG
glfwWindowHint (GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
#endif /* DEBUG */
// create window, size doesn't matter as long as we don't show it
this->m_window = glfwCreateWindow (640, 480, windowTitle, nullptr, nullptr);
if (this->m_window == nullptr)
sLog.exception ("Cannot create window");
// make context current, required for glew initialization
glfwMakeContextCurrent (this->m_window);
// initialize glew for rendering
GLenum result = glewInit ();
if (result != GLEW_OK)
sLog.error("Failed to initialize GLEW: ", glewGetErrorString (result));
// initialize free image
FreeImage_Initialise (TRUE);
// setup output
if (context.settings.render.mode == CApplicationContext::EXPLICIT_WINDOW ||
context.settings.render.mode == CApplicationContext::NORMAL_WINDOW)
{
m_output = new WallpaperEngine::Render::Drivers::Output::CGLFWWindowOutput (context, *this);
}
else
{
m_output = new WallpaperEngine::Render::Drivers::Output::CX11Output (context, *this);
}
}
CX11OpenGLDriver::~CX11OpenGLDriver ()
{
glfwTerminate ();
FreeImage_DeInitialise();
}
Detectors::CFullScreenDetector& CX11OpenGLDriver::getFullscreenDetector ()
{
return this->m_fullscreenDetector;
}
Output::COutput& CX11OpenGLDriver::getOutput ()
{
return *this->m_output;
}
float CX11OpenGLDriver::getRenderTime () const
{
return (float) glfwGetTime ();
}
bool CX11OpenGLDriver::closeRequested ()
{
return glfwWindowShouldClose (this->m_window);
}
void CX11OpenGLDriver::resizeWindow (glm::ivec2 size)
{
glfwSetWindowSize (this->m_window, size.x, size.y);
}
void CX11OpenGLDriver::resizeWindow (glm::ivec4 sizeandpos)
{
glfwSetWindowPos (this->m_window, sizeandpos.x, sizeandpos.y);
glfwSetWindowSize (this->m_window, sizeandpos.z, sizeandpos.w);
}
void CX11OpenGLDriver::showWindow ()
{
glfwShowWindow (this->m_window);
}
void CX11OpenGLDriver::hideWindow ()
{
glfwHideWindow (this->m_window);
}
glm::ivec2 CX11OpenGLDriver::getFramebufferSize () const
{
glm::ivec2 size;
glfwGetFramebufferSize (this->m_window, &size.x, &size.y);
return size;
}
uint32_t CX11OpenGLDriver::getFrameCounter () const
{
return this->m_frameCounter;
}
void CX11OpenGLDriver::dispatchEventQueue()
{
static float startTime, endTime, minimumTime = 1.0f / this->m_context.settings.render.maximumFPS;
// get the start time of the frame
startTime = this->getRenderTime ();
// clear the screen
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (const auto& viewport : this->m_output->getViewports ())
this->getApp ().update (viewport.second);
// read the full texture into the image
if (this->m_output->haveImageBuffer ())
glReadPixels (
0, 0, this->m_output->getFullWidth (), this->m_output->getFullHeight (), GL_BGRA, GL_UNSIGNED_BYTE,
this->m_output->getImageBuffer ()
);
// TODO: FRAMETIME CONTROL SHOULD GO BACK TO THE CWALLPAPAERAPPLICATION ONCE ACTUAL PARTICLES ARE IMPLEMENTED
// TODO: AS THOSE, MORE THAN LIKELY, WILL REQUIRE OF A DIFFERENT PROCESSING RATE
// update the output with the given image
this->m_output->updateRender ();
// do buffer swapping first
glfwSwapBuffers (this->m_window);
// poll for events
glfwPollEvents ();
// increase frame counter
this->m_frameCounter ++;
// get the end time of the frame
endTime = this->getRenderTime ();
// ensure the frame time is correct to not overrun FPS
if ((endTime - startTime) < minimumTime)
usleep ((minimumTime - (endTime - startTime)) * CLOCKS_PER_SEC);
}
void* CX11OpenGLDriver::getProcAddress (const char* name) const
{
return reinterpret_cast <void*> (glfwGetProcAddress (name));
}
GLFWwindow* CX11OpenGLDriver::getWindow ()
{
return this->m_window;
}