Output rendering is now responsibility of the drivers (as it should be) instead of being handled by the CRenderContext

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
Alexis Maiquez 2023-04-22 22:44:33 +02:00
parent 21bcb7008f
commit bd6fd9a100
16 changed files with 144 additions and 179 deletions

View File

@ -27,6 +27,15 @@ namespace WallpaperEngine::Application
this->setupProperties ();
}
CWallpaperApplication::~CWallpaperApplication ()
{
delete context;
delete videoDriver;
delete audioContext;
delete audioDriver;
delete inputContext;
}
void CWallpaperApplication::setupContainer (CCombinedContainer& container, const std::string& bg) const
{
std::filesystem::path basepath = bg;
@ -322,9 +331,34 @@ namespace WallpaperEngine::Application
this->m_defaultBackground->getWallpaper (), *context, *audioContext
));
static time_t seconds;
static struct tm* timeinfo;
while (this->m_context.state.general.keepRunning && !videoDriver->closeRequested ())
{
// update g_Daytime
time (&seconds);
timeinfo = localtime(&seconds);
g_Daytime = ((timeinfo->tm_hour * 60) + timeinfo->tm_min) / (24.0 * 60.0);
// keep track of the previous frame's time
g_TimeLast = g_Time;
// calculate the current time value
g_Time = videoDriver->getRenderTime ();
// update audio recorder
audioDriver->update ();
// update input information
inputContext->update ();
// process driver events
videoDriver->dispatchEventQueue ();
if (!this->m_context.settings.screenshot.take || videoDriver->getFrameCounter () < 5)
continue;
this->takeScreenshot (*context, this->m_context.settings.screenshot.path, this->m_context.settings.screenshot.format);
this->m_context.settings.screenshot.take = false;
}
// ensure this is updated as sometimes it might not come from a signal
this->m_context.state.general.keepRunning = false;
@ -333,33 +367,10 @@ namespace WallpaperEngine::Application
SDL_Quit ();
}
void CWallpaperApplication::update()
void CWallpaperApplication::update(Render::Drivers::Output::COutputViewport* viewport)
{
static time_t seconds;
static struct tm* timeinfo;
// update g_Daytime
time (&seconds);
timeinfo = localtime(&seconds);
g_Daytime = ((timeinfo->tm_hour * 60) + timeinfo->tm_min) / (24.0 * 60.0);
// keep track of the previous frame's time
g_TimeLast = g_Time;
// calculate the current time value
g_Time = videoDriver->getRenderTime ();
// update audio recorder
audioDriver->update ();
// update input information
inputContext->update ();
// render the scene
context->render ();
if (!this->m_context.settings.screenshot.take || videoDriver->getFrameCounter () < 5)
return;
this->takeScreenshot (*context, this->m_context.settings.screenshot.path, this->m_context.settings.screenshot.format);
this->m_context.settings.screenshot.take = false;
context->render (viewport);
}
void CWallpaperApplication::signal (int signal)

View File

@ -39,6 +39,7 @@ namespace WallpaperEngine::Application
{
public:
explicit CWallpaperApplication (CApplicationContext& context);
~CWallpaperApplication ();
/**
* Shows the application until it's closed
@ -65,7 +66,7 @@ namespace WallpaperEngine::Application
/**
* Renders a frame
*/
void update();
void update(Render::Drivers::Output::COutputViewport* viewport);
/**
* Gets the output
*/
@ -121,7 +122,5 @@ namespace WallpaperEngine::Application
WallpaperEngine::Audio::Drivers::CSDLAudioDriver* audioDriver;
WallpaperEngine::Render::CRenderContext* context;
WallpaperEngine::Audio::CAudioContext* audioContext;
std::vector<std::string> screenshotOutputsDone;
};
}

View File

@ -14,16 +14,8 @@ void CWaylandMouseInput::update ()
glm::dvec2 CWaylandMouseInput::position() const
{
if (!waylandDriver->viewportInFocus)
return {0, 0};
for (auto& o : waylandDriver->m_screens)
{
if (!o->rendering)
continue;
return o == waylandDriver->viewportInFocus ? o->mousePos : glm::dvec2{-1337, -1337};
}
if (waylandDriver->viewportInFocus && waylandDriver->viewportInFocus->rendering)
return waylandDriver->viewportInFocus->mousePos;
return {0, 0};
}

View File

@ -21,51 +21,30 @@ namespace WallpaperEngine::Render
{
}
void CRenderContext::render ()
void CRenderContext::render (Drivers::Output::COutputViewport* viewport)
{
bool firstFrame = true;
bool renderFrame = true;
for (const auto& cur : this->getOutput ().getViewports ())
{
cur.second->makeCurrent ();
viewport->makeCurrent ();
#if !NDEBUG
std::string str = "Rendering to output " + cur.first;
std::string str = "Rendering to output " + viewport->name;
glPushDebugGroup (GL_DEBUG_SOURCE_APPLICATION, 0, -1, str.c_str ());
glPushDebugGroup (GL_DEBUG_SOURCE_APPLICATION, 0, -1, str.c_str ());
#endif /* DEBUG */
// search the background in the viewport selection
auto ref = this->m_wallpapers.find (cur.first);
// render the background
if (ref != this->m_wallpapers.end ())
ref->second->render (cur.second->viewport, this->getOutput ().renderVFlip (), renderFrame, firstFrame);
else
this->m_defaultWallpaper->render (
cur.second->viewport, this->getOutput ().renderVFlip (), renderFrame, firstFrame
);
// scenes need to render a new frame for each viewport as they produce different results
// but videos should only be rendered once per group of viewports
firstFrame = false;
// search the background in the viewport selection
auto ref = this->m_wallpapers.find (viewport->name);
// render the background
if (ref != this->m_wallpapers.end ())
ref->second->render (viewport->viewport, this->getOutput ().renderVFlip ());
else
this->m_defaultWallpaper->render (viewport->viewport, this->getOutput ().renderVFlip ());
#if !NDEBUG
glPopDebugGroup ();
glPopDebugGroup ();
#endif /* DEBUG */
cur.second->swapOutput ();
}
// read the full texture into the image
if (this->getOutput ().haveImageBuffer ())
glReadPixels (
0, 0, this->getOutput ().getFullWidth (), this->getOutput ().getFullHeight (), GL_BGRA, GL_UNSIGNED_BYTE,
this->getOutput ().getImageBuffer ()
);
// update the output with the given image
this->getOutput ().updateRender ();
// finally swap buffers
this->m_driver.swapBuffers ();
viewport->swapOutput ();
}
void CRenderContext::setDefaultWallpaper (CWallpaper* wallpaper)

View File

@ -39,7 +39,7 @@ namespace WallpaperEngine
public:
CRenderContext (Drivers::CVideoDriver& driver, Input::CInputContext& input, CWallpaperApplication& app);
void render ();
void render (Drivers::Output::COutputViewport* viewport);
void setDefaultWallpaper (CWallpaper* wallpaper);
void setWallpaper (const std::string& display, CWallpaper* wallpaper);
[[nodiscard]] Input::CInputContext& getInputContext () const;

View File

@ -211,10 +211,9 @@ void CWallpaper::setDestinationFramebuffer (GLuint framebuffer)
this->m_destFramebuffer = framebuffer;
}
void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool newFrame)
void CWallpaper::render (glm::ivec4 viewport, bool vflip)
{
if (renderFrame)
this->renderFrame (viewport);
this->renderFrame (viewport);
uint32_t projectionWidth = this->getWidth ();
uint32_t projectionHeight = this->getHeight ();
@ -293,9 +292,6 @@ void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool
glBindVertexArray (this->m_vaoBuffer);
if (newFrame)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable (GL_BLEND);
glDisable (GL_DEPTH_TEST);
// do not use any shader

View File

@ -37,7 +37,7 @@ namespace WallpaperEngine::Render
/**
* Performs a render pass of the wallpaper
*/
void render (glm::ivec4 viewport, bool vflip, bool renderFrame = true, bool newFrame = true);
void render (glm::ivec4 viewport, bool vflip);
/**
* @return The container to resolve files for this wallpaper

View File

@ -7,6 +7,10 @@ CVideoDriver::CVideoDriver (CWallpaperApplication& app) :
{
}
CVideoDriver::~CVideoDriver ()
{
}
CWallpaperApplication& CVideoDriver::getApp () const
{
return this->m_app;

View File

@ -21,6 +21,7 @@ namespace WallpaperEngine::Render::Drivers
{
public:
CVideoDriver (CWallpaperApplication& app);
virtual ~CVideoDriver ();
/**
* @return The fullscreen detector this video driver uses
@ -58,10 +59,6 @@ namespace WallpaperEngine::Render::Drivers
* @return The size of the framebuffer available for the driver
*/
[[nodiscard]] virtual glm::ivec2 getFramebufferSize () const = 0;
/**
* Performs buffer swapping
*/
virtual void swapBuffers () = 0;
/**
* @return The number of rendered frames since the start of the driver
*/
@ -74,7 +71,7 @@ namespace WallpaperEngine::Render::Drivers
/**
* Process events on the driver and renders a frame
*/
virtual void dispatchEventQueue() const = 0;
virtual void dispatchEventQueue() = 0;
/**
* @return The app that owns this driver
*/

View File

@ -129,31 +129,18 @@ void CWaylandOpenGLDriver::initEGL()
if (!eglGetPlatformDisplayEXT || !m_eglContext.eglCreatePlatformWindowSurfaceEXT)
sLog.exception("EGL did not return EXT proc pointers!");
auto deinitEGL = [&] () -> void {
eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_eglContext.display)
eglTerminate(m_eglContext.display);
eglReleaseThread();
};
m_eglContext.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_waylandContext.display, nullptr);
if (m_eglContext.display == EGL_NO_DISPLAY) {
deinitEGL();
if (m_eglContext.display == EGL_NO_DISPLAY)
sLog.exception("eglGetPlatformDisplayEXT failed!");
}
if (!eglInitialize(m_eglContext.display, nullptr, nullptr)) {
deinitEGL();
if (!eglInitialize(m_eglContext.display, nullptr, nullptr))
sLog.exception("eglInitialize failed!");
}
const std::string CLIENTEXTENSIONSPOSTINIT = std::string(eglQueryString(m_eglContext.display, EGL_EXTENSIONS));
if (CLIENTEXTENSIONSPOSTINIT.find("EGL_KHR_create_context") == std::string::npos) {
deinitEGL();
if (CLIENTEXTENSIONSPOSTINIT.find("EGL_KHR_create_context") == std::string::npos)
sLog.exception("EGL_KHR_create_context not supported!");
}
EGLint matchedConfigs = 0;
const EGLint CONFIG_ATTRIBUTES[] = {
@ -166,20 +153,14 @@ void CWaylandOpenGLDriver::initEGL()
EGL_NONE,
};
if (!eglChooseConfig(m_eglContext.display, CONFIG_ATTRIBUTES, &m_eglContext.config, 1, &matchedConfigs)) {
deinitEGL();
if (!eglChooseConfig(m_eglContext.display, CONFIG_ATTRIBUTES, &m_eglContext.config, 1, &matchedConfigs))
sLog.exception("eglChooseConfig failed!");
}
if (matchedConfigs == 0) {
deinitEGL();
if (matchedConfigs == 0)
sLog.exception("eglChooseConfig failed! (matched 0 configs)");
}
if (!eglBindAPI(EGL_OPENGL_API)) {
deinitEGL();
if (!eglBindAPI(EGL_OPENGL_API))
sLog.exception("eglBindAPI failed!");
}
const EGLint CONTEXT_ATTRIBUTES[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
@ -187,23 +168,15 @@ void CWaylandOpenGLDriver::initEGL()
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
EGL_NONE,
};
m_eglContext.context = eglCreateContext(m_eglContext.display, m_eglContext.config, EGL_NO_CONTEXT, CONTEXT_ATTRIBUTES);
if (m_eglContext.context == EGL_NO_CONTEXT) {
sLog.error("eglCreateContext error " + std::to_string(eglGetError()));
deinitEGL();
sLog.exception("eglCreateContext failed!");
}
}
void CWaylandOpenGLDriver::finishEGL()
{
eglMakeCurrent(m_eglContext.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(m_eglContext.display, m_eglContext.context);
eglTerminate(m_eglContext.display);
eglReleaseThread();
}
void CWaylandOpenGLDriver::onLayerClose(Output::CWaylandOutputViewport* viewport)
{
sLog.error ("Compositor closed our LS, freeing data...");
@ -222,8 +195,11 @@ void CWaylandOpenGLDriver::onLayerClose(Output::CWaylandOutputViewport* viewport
// remove the output from the list
std::remove (this->m_screens.begin (), this->m_screens.end (), viewport);
// TODO: DELETE FROM VIEWPORT LIST
// reset the viewports
this->getOutput ().reset ();
// finally free memory used by the viewport
delete viewport;
}
@ -231,6 +207,7 @@ CWaylandOpenGLDriver::CWaylandOpenGLDriver(CApplicationContext& context, CWallpa
m_frameCounter(0),
m_fullscreenDetector (context, *this),
m_output (context, *this),
m_requestedExit (false),
CVideoDriver (app)
{
m_waylandContext.display = wl_display_connect (nullptr);
@ -263,19 +240,7 @@ CWaylandOpenGLDriver::CWaylandOpenGLDriver(CApplicationContext& context, CWallpa
}
if (!any)
{
const auto cur = context.settings.general.screenBackgrounds.find ("auto");
if (cur != context.settings.general.screenBackgrounds.end ())
{
// initializes the default screen only...
m_screens [0]->setupLS ();
any = true;
}
}
if (!any)
sLog.exception("No outputs could be initialized!");
sLog.exception("No outputs could be initialized, please check the parameters and try again");
GLenum result = glewInit ();
@ -285,12 +250,37 @@ CWaylandOpenGLDriver::CWaylandOpenGLDriver(CApplicationContext& context, CWallpa
FreeImage_Initialise (TRUE);
}
void CWaylandOpenGLDriver::dispatchEventQueue() const
CWaylandOpenGLDriver::~CWaylandOpenGLDriver ()
{
// render one frame to force drawing the screens
this->getApp ().update ();
eglMakeCurrent (EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
wl_display_dispatch(m_waylandContext.display);
if (m_eglContext.context != EGL_NO_CONTEXT)
eglDestroyContext (m_eglContext.display, m_eglContext.context);
eglTerminate (m_eglContext.display);
eglReleaseThread ();
// disconnect from wayland display
if (this->m_waylandContext.display)
wl_display_disconnect (this->m_waylandContext.display);
}
void CWaylandOpenGLDriver::dispatchEventQueue()
{
static bool initialized = false;
if (!initialized)
{
initialized = true;
for (const auto& viewport : this->getOutput ().getViewports ())
this->getApp ().update (viewport.second);
}
if (wl_display_dispatch(m_waylandContext.display) == -1)
m_requestedExit = true;
m_frameCounter ++;
}
Detectors::CFullScreenDetector& CWaylandOpenGLDriver::getFullscreenDetector ()
@ -310,7 +300,7 @@ float CWaylandOpenGLDriver::getRenderTime () const
bool CWaylandOpenGLDriver::closeRequested ()
{
return false;
return this->m_requestedExit;
}
void CWaylandOpenGLDriver::resizeWindow (glm::ivec2 size)
@ -334,11 +324,6 @@ glm::ivec2 CWaylandOpenGLDriver::getFramebufferSize () const
return glm::ivec2{0, 0};
}
void CWaylandOpenGLDriver::swapBuffers ()
{
m_frameCounter ++;
}
uint32_t CWaylandOpenGLDriver::getFrameCounter () const
{
return m_frameCounter;

View File

@ -75,9 +75,8 @@ namespace WallpaperEngine::Render::Drivers
void showWindow () override;
void hideWindow () override;
glm::ivec2 getFramebufferSize () const override;
void swapBuffers () override;
uint32_t getFrameCounter () const override;
void dispatchEventQueue() const override;
void dispatchEventQueue() override;
[[nodiscard]] void* getProcAddress (const char* name) const override;
void onLayerClose(Output::CWaylandOutputViewport*);
@ -101,6 +100,7 @@ namespace WallpaperEngine::Render::Drivers
SEGLContext m_eglContext;
/** The Wayland context in use */
SWaylandContext m_waylandContext;
mutable bool m_requestedExit;
void initEGL();
void finishEGL();

View File

@ -135,27 +135,37 @@ glm::ivec2 CX11OpenGLDriver::getFramebufferSize () const
return size;
}
void CX11OpenGLDriver::swapBuffers ()
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 ()
);
// 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 ++;
}
uint32_t CX11OpenGLDriver::getFrameCounter () const
{
return this->m_frameCounter;
}
void CX11OpenGLDriver::dispatchEventQueue() const
{
static float startTime, endTime, minimumTime = 1.0f / this->m_context.settings.render.maximumFPS;
// get the start time of the frame
startTime = this->getRenderTime ();
this->getApp ().update ();
// get the end time of the frame
endTime = this->getRenderTime ();

View File

@ -34,9 +34,8 @@ namespace WallpaperEngine::Render::Drivers
void showWindow () override;
void hideWindow () override;
[[nodiscard]] glm::ivec2 getFramebufferSize () const override;
void swapBuffers () override;
[[nodiscard]] uint32_t getFrameCounter () const override;
void dispatchEventQueue() const override;
void dispatchEventQueue() override;
[[nodiscard]] void* getProcAddress (const char* name) const override;
GLFWwindow* getWindow ();

View File

@ -1,6 +1,7 @@
#include "common.h"
#include "CWaylandOutput.h"
#include "../CWaylandOpenGLDriver.h"
#include "WallpaperEngine/Application/CWallpaperApplication.h"
using namespace WallpaperEngine::Render::Drivers::Output;
@ -26,9 +27,9 @@ void CWaylandOutput::updateViewports()
m_viewports[o->name] = o;
fullw = fullw + glm::ivec2{o->lsSize.x * o->scale, 0};
if (o->lsSize.y > fullw.y)
fullw.y = o->lsSize.y;
fullw = fullw + glm::ivec2{o->size.x * o->scale, 0};
if (o->size.y > fullw.y)
fullw.y = o->size.y;
}
m_fullWidth = fullw.x;

View File

@ -100,7 +100,7 @@ static void surfaceFrameCallback(void *data, struct wl_callback *cb, uint32_t ti
viewport->frameCallback = nullptr;
viewport->rendering = true;
viewport->getDriver ()->getApp ().update ();
viewport->getDriver ()->getApp ().update (viewport);
viewport->rendering = false;
float renderTime = viewport->getDriver ()->getRenderTime();
@ -111,7 +111,8 @@ static void surfaceFrameCallback(void *data, struct wl_callback *cb, uint32_t ti
viewport->lastTime = renderTime;
}
const struct wl_callback_listener frameListener = {
const struct wl_callback_listener frameListener =
{
.done = surfaceFrameCallback
};
@ -145,7 +146,7 @@ CWaylandOutputViewport::CWaylandOutputViewport (CWaylandOpenGLDriver* driver, ui
void CWaylandOutputViewport::setupLS ()
{
surface = wl_compositor_create_surface(m_driver->getWaylandContext()->compositor);
layerSurface = zwlr_layer_shell_v1_get_layer_surface(m_driver->getWaylandContext()->layerShell, surface, this->output, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "linux-wallpaperengine");
layerSurface = zwlr_layer_shell_v1_get_layer_surface(m_driver->getWaylandContext()->layerShell, surface, output, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "linux-wallpaperengine");
if (!layerSurface)
sLog.exception("Failed to get a layer surface");
@ -164,7 +165,6 @@ void CWaylandOutputViewport::setupLS ()
eglWindow = wl_egl_window_create(surface, size.x * scale, size.y * scale);
eglSurface = m_driver->getEGLContext ()->eglCreatePlatformWindowSurfaceEXT(m_driver->getEGLContext ()->display, m_driver->getEGLContext ()->config, eglWindow, nullptr);
lsSize = size;
wl_surface_commit(surface);
wl_display_roundtrip(m_driver->getWaylandContext()->display);
wl_display_flush(m_driver->getWaylandContext()->display);
@ -186,8 +186,7 @@ void CWaylandOutputViewport::setupLS ()
minimumTime = 1.0f / m_driver->getApp ().getContext().settings.render.maximumFPS;
// reset the output to notice the new viewport
m_driver->getOutput ().reset ();
this->m_driver->getOutput ().reset ();
}
CWaylandOpenGLDriver* CWaylandOutputViewport::getDriver ()
@ -228,11 +227,5 @@ void CWaylandOutputViewport::resize ()
wl_egl_window_resize(this->eglWindow, this->size.x * this->scale, this->size.y * this->scale, 0, 0);
if (this->frameCallback)
{
wl_callback_destroy(this->frameCallback);
this->frameCallback = nullptr;
}
this->getDriver ()->getOutput().reset();
}

View File

@ -35,7 +35,6 @@ namespace WallpaperEngine::Render::Drivers
wl_output* output;
glm::ivec2 size;
glm::ivec2 lsSize;
uint32_t waylandName;
int scale = 1;
bool initialized = false;