~ reorganized context initialization so opengl is ready

~ moved pixmap, gc and image creation to the initialization
  TODO: SUPPORT SCREEN SIZE CHANGES (THIS MIGHT NEED REINITIALIZATION OF THINGS)
~ moved fbo creation to initialization as it won't change anymore
~ reverted render code to the original loop as now the framebuffer is exactly as big as the whole display
~ moved glReadPixels off the wallpaper as that's code is exclusively used for screen rendering and not general rendering
~ XChangeProperty forces the update of the background, otherwise the compositor stops refreshing the screen and the background gets stuck
~ updated viewport variables to be integers instead of floats
~ reverted frame rendering code to be simpler and added the option to specify a framebuffer as target instead of screen

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
Alexis Maiquez 2022-02-28 02:03:47 +01:00
parent a2222b05ef
commit 5bc0525493
9 changed files with 126 additions and 102 deletions

View File

@ -231,8 +231,6 @@ int main (int argc, char* argv[])
// parse the project.json file // parse the project.json file
auto project = WallpaperEngine::Core::CProject::fromFile ("project.json", containers); auto project = WallpaperEngine::Core::CProject::fromFile ("project.json", containers);
WallpaperEngine::Render::CWallpaper* wallpaper; WallpaperEngine::Render::CWallpaper* wallpaper;
// initialize custom context class
WallpaperEngine::Render::CContext* context = new WallpaperEngine::Render::CContext (screens);
// auto projection = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection (); // auto projection = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
// create the window! // create the window!
@ -250,8 +248,6 @@ int main (int argc, char* argv[])
// initialize inputs // initialize inputs
CMouseInput* mouseInput = new CMouseInput (window); CMouseInput* mouseInput = new CMouseInput (window);
context->setMouse (mouseInput);
glfwMakeContextCurrent (window); glfwMakeContextCurrent (window);
// TODO: FIGURE THESE OUT BASED ON THE SCREEN // TODO: FIGURE THESE OUT BASED ON THE SCREEN
@ -260,9 +256,8 @@ int main (int argc, char* argv[])
// get the real framebuffer size // get the real framebuffer size
glfwGetFramebufferSize (window, &windowWidth, &windowHeight); glfwGetFramebufferSize (window, &windowWidth, &windowHeight);
// set the default viewport
context->setDefaultViewport ({0, 0, windowWidth, windowHeight});
// initialize glew
if (glewInit () != GLEW_OK) if (glewInit () != GLEW_OK)
{ {
fprintf (stderr, "Failed to initialize GLEW"); fprintf (stderr, "Failed to initialize GLEW");
@ -270,6 +265,13 @@ int main (int argc, char* argv[])
return 3; return 3;
} }
// initialize custom context class
WallpaperEngine::Render::CContext* context = new WallpaperEngine::Render::CContext (screens);
// initialize mouse support
context->setMouse (mouseInput);
// set the default viewport
context->setDefaultViewport ({0, 0, windowWidth, windowHeight});
if (project->getType () == "scene") if (project->getType () == "scene")
{ {
WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> (); WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ();

View File

@ -25,27 +25,34 @@ void CContext::initializeViewports ()
if (this->m_isRootWindow == false || this->m_screens.empty () == true) if (this->m_isRootWindow == false || this->m_screens.empty () == true)
return; return;
Display* display = XOpenDisplay (nullptr); this->m_display = XOpenDisplay (nullptr);
int xrandr_result, xrandr_error; int xrandr_result, xrandr_error;
if (!XRRQueryExtension (display, &xrandr_result, &xrandr_error)) if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
{ {
std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl; std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl;
return; return;
} }
int fullWidth = DisplayWidth (display, DefaultScreen (display)); Window root = DefaultRootWindow (this->m_display);
int fullHeight = DisplayHeight (display, DefaultScreen (display)); int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
XRRScreenResources* screenResources = XRRGetScreenResources (display, DefaultRootWindow (display)); int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, DefaultRootWindow (this->m_display));
// there are some situations where xrandr returns null (like screen not using the extension) // there are some situations where xrandr returns null (like screen not using the extension)
if (screenResources == nullptr) if (screenResources == nullptr)
return; return;
// create the pixmap and gc used for this display, most situations only have one "display"
this->m_pixmap = XCreatePixmap (this->m_display, DefaultRootWindow (this->m_display), fullWidth, fullHeight, 24);
this->m_gc = XCreateGC (this->m_display, this->m_pixmap, 0, nullptr);
// fill the whole pixmap with black for now
XFillRectangle (this->m_display, this->m_pixmap, this->m_gc, 0, 0, fullWidth, fullHeight);
for (int i = 0; i < screenResources->noutput; i ++) for (int i = 0; i < screenResources->noutput; i ++)
{ {
XRROutputInfo* info = XRRGetOutputInfo (display, screenResources, screenResources->outputs [i]); XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
// there are some situations where xrandr returns null (like screen not using the extension) // there are some situations where xrandr returns null (like screen not using the extension)
if (info == nullptr) if (info == nullptr)
@ -58,11 +65,11 @@ void CContext::initializeViewports ()
{ {
if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0) if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0)
{ {
XRRCrtcInfo* crtc = XRRGetCrtcInfo (display, screenResources, info->crtc); XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl; std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl;
glm::vec4 viewport = { glm::ivec4 viewport = {
crtc->x, fullHeight - (crtc->y + crtc->height), crtc->width, crtc->height crtc->x, fullHeight - (crtc->y + crtc->height), crtc->width, crtc->height
}; };
@ -77,6 +84,17 @@ void CContext::initializeViewports ()
XRRFreeScreenResources (screenResources); XRRFreeScreenResources (screenResources);
// create the fbo that will handle the screen
this->m_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, fullWidth, fullHeight, fullWidth, fullHeight);
// set the window background so the pixmap is drawn
XSetWindowBackgroundPixmap(this->m_display, root, this->m_pixmap);
this->m_imageData = new char [fullWidth * fullHeight * 4];
// create the image for X11 to be able to copy it over
this->m_image = XCreateImage (this->m_display, CopyFromParent, 24, ZPixmap, 0, this->m_imageData, fullWidth, fullHeight, 32, 0);
// Cause of issue for issue #59 origial issue // Cause of issue for issue #59 origial issue
// glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display))); // glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display)));
} }
@ -88,43 +106,40 @@ void CContext::render ()
if (this->m_viewports.empty () == false) if (this->m_viewports.empty () == false)
{ {
static Display* display = XOpenDisplay (nullptr); bool firstFrame = true;
bool renderFrame = true;
auto cur = this->m_viewports.begin (); auto cur = this->m_viewports.begin ();
auto end = this->m_viewports.end (); auto end = this->m_viewports.end ();
int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
Window root = DefaultRootWindow (this->m_display);
Window root = DefaultRootWindow(display);
int windowWidth = 1920, windowHeight = 1080;
int fullWidth = DisplayWidth (display, DefaultScreen (display));
int fullHeight = DisplayHeight (display, DefaultScreen (display));
Pixmap pm = XCreatePixmap(display, root, fullWidth, fullHeight, 24);
GC gc = XCreateGC(display, pm, 0, NULL);
XFillRectangle(display, pm, gc, 0, 0, fullWidth, fullHeight);
char* image_data;
image_data = new char[windowWidth*windowHeight*4];
this->m_wallpaper->render (this->m_defaultViewport, true, image_data);
XImage* image = XCreateImage(display, CopyFromParent, 24, ZPixmap, 0, (char *)image_data, windowWidth, windowHeight, 32, 0);
for (; cur != end; cur ++) for (; cur != end; cur ++)
{ {
XPutImage(display, pm, gc, image, 0, 0, (*cur).x, (*cur).y, windowWidth, windowHeight); // render the background
this->m_wallpaper->render (*cur, 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;
renderFrame = !this->m_wallpaper->is <CVideo> ();
} }
// read the full texture into the image
glReadPixels (0, 0, fullWidth, fullHeight, GL_BGRA, GL_UNSIGNED_BYTE, (void*) this->m_imageData);
// put the image back into the screen
XPutImage (this->m_display, this->m_pixmap, this->m_gc, this->m_image, 0, 0, 0, 0, fullWidth, fullHeight);
// _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to
// edit the background. Without these, other programs will clear the screen. // edit the background. Without these, other programs will clear the screen.
Atom prop_root = XInternAtom(display, "_XROOTPMAP_ID", False); // it also forces the compositor to refresh the background (tested with picom)
Atom prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", False); Atom prop_root = XInternAtom(this->m_display, "_XROOTPMAP_ID", False);
XChangeProperty(display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1); Atom prop_esetroot = XInternAtom(this->m_display, "ESETROOT_PMAP_ID", False);
XChangeProperty(display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1); XChangeProperty(this->m_display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
XChangeProperty(this->m_display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
XSetWindowBackgroundPixmap(display, root, pm); XClearWindow(this->m_display, root);
XClearWindow(display, root); XFlush(this->m_display);
XFlush(display);
XDestroyImage(image);
XFreePixmap(display, pm);
XFreeGC(display, gc);
} }
else else
this->m_wallpaper->render (this->m_defaultViewport); this->m_wallpaper->render (this->m_defaultViewport);
@ -133,6 +148,22 @@ void CContext::render ()
void CContext::setWallpaper (CWallpaper* wallpaper) void CContext::setWallpaper (CWallpaper* wallpaper)
{ {
this->m_wallpaper = wallpaper; this->m_wallpaper = wallpaper;
// update the wallpaper's texcoords based on the mode we're running
if (this->m_screens.empty () == false)
{
GLfloat texCoords [] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
this->m_wallpaper->updateTexCoord (texCoords, sizeof (texCoords));
this->m_wallpaper->setDestinationFramebuffer (this->m_fbo->getFramebuffer ());
}
} }
void CContext::setDefaultViewport (glm::vec4 defaultViewport) void CContext::setDefaultViewport (glm::vec4 defaultViewport)

View File

@ -5,6 +5,7 @@
#include "WallpaperEngine/Input/CMouseInput.h" #include "WallpaperEngine/Input/CMouseInput.h"
#include "CWallpaper.h" #include "CWallpaper.h"
#include <X11/Xlib.h>
using namespace WallpaperEngine::Input; using namespace WallpaperEngine::Input;
@ -23,9 +24,16 @@ namespace WallpaperEngine::Render
void setDefaultViewport (glm::vec4 defaultViewport); void setDefaultViewport (glm::vec4 defaultViewport);
CMouseInput* getMouse () const; CMouseInput* getMouse () const;
void setMouse (CMouseInput* mouse); void setMouse (CMouseInput* mouse);
private: private:
Display* m_display;
Pixmap m_pixmap;
GC m_gc;
XImage* m_image;
char* m_imageData;
CFBO* m_fbo;
std::vector <std::string> m_screens; std::vector <std::string> m_screens;
std::vector <glm::vec4> m_viewports; std::vector <glm::ivec4> m_viewports;
glm::vec4 m_defaultViewport; glm::vec4 m_defaultViewport;
CWallpaper* m_wallpaper; CWallpaper* m_wallpaper;
CMouseInput* m_mouse; CMouseInput* m_mouse;

View File

@ -56,7 +56,7 @@ CCamera* CScene::getCamera () const
return this->m_camera; return this->m_camera;
} }
void CScene::renderFrame (glm::vec4 viewport) void CScene::renderFrame (glm::ivec4 viewport)
{ {
auto projection = this->getScene ()->getOrthogonalProjection (); auto projection = this->getScene ()->getOrthogonalProjection ();
auto cur = this->m_objects.begin (); auto cur = this->m_objects.begin ();
@ -82,7 +82,7 @@ void CScene::renderFrame (glm::vec4 viewport)
glViewport (0, 0, projection->getWidth (), projection->getHeight ()); glViewport (0, 0, projection->getWidth (), projection->getHeight ());
} }
void CScene::updateMouse (glm::vec4 viewport) void CScene::updateMouse (glm::ivec4 viewport)
{ {
// projection also affects the mouse position // projection also affects the mouse position
auto projection = this->getScene ()->getOrthogonalProjection (); auto projection = this->getScene ()->getOrthogonalProjection ();

View File

@ -24,8 +24,8 @@ namespace WallpaperEngine::Render
glm::vec2* getMousePosition (); glm::vec2* getMousePosition ();
protected: protected:
void renderFrame (glm::vec4 viewport) override; void renderFrame (glm::ivec4 viewport) override;
void updateMouse (glm::vec4 viewport); void updateMouse (glm::ivec4 viewport);
friend class CWallpaper; friend class CWallpaper;

View File

@ -115,7 +115,7 @@ void CVideo::setSize (int width, int height)
SWS_BILINEAR, NULL, NULL, NULL); SWS_BILINEAR, NULL, NULL, NULL);
} }
void CVideo::renderFrame (glm::vec4 viewport) void CVideo::renderFrame (glm::ivec4 viewport)
{ {
// do not render using the CWallpaper function, just use this one // do not render using the CWallpaper function, just use this one
this->setSize (m_codecCtx->width, m_codecCtx->height); this->setSize (m_codecCtx->width, m_codecCtx->height);

View File

@ -25,7 +25,7 @@ namespace WallpaperEngine::Render
int getHeight (); int getHeight ();
protected: protected:
void renderFrame (glm::vec4 viewport) override; void renderFrame (glm::ivec4 viewport) override;
friend class CWallpaper; friend class CWallpaper;

View File

@ -12,7 +12,8 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CCont
m_container (container), m_container (container),
m_wallpaperData (wallpaperData), m_wallpaperData (wallpaperData),
m_type (std::move(type)), m_type (std::move(type)),
m_context (context) m_context (context),
m_destFramebuffer (GL_NONE)
{ {
this->setupShaders (); this->setupShaders ();
@ -185,8 +186,19 @@ void CWallpaper::setupShaders ()
this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord"); this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
} }
void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_data) void CWallpaper::updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const
{ {
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glBufferData (GL_ARRAY_BUFFER, size, texCoords, GL_STATIC_DRAW);
}
void CWallpaper::setDestinationFramebuffer (GLuint framebuffer)
{
this->m_destFramebuffer = framebuffer;
}
void CWallpaper::render (glm::ivec4 viewport, bool renderFrame, bool newFrame)
{
if (renderFrame == true)
this->renderFrame (viewport); this->renderFrame (viewport);
int windowWidth = 1920; int windowWidth = 1920;
@ -257,53 +269,13 @@ void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_
glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer); glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW); glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
// we only want texCoords to be set once
static bool setTexCoords = true;
if (setTexCoords)
{
setTexCoords = false;
if (drawToBackground)
{
// Need to flip the image (FB stores the image upside down)
GLfloat texCoords [] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
}
else
{
GLfloat texCoords [] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
}
}
glViewport (viewport.x, viewport.y, viewport.z, viewport.w); glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
static CFBO* screen_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight); glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer);
if (drawToBackground)
// write to screen buffer
glBindFramebuffer (GL_FRAMEBUFFER, screen_fbo->getFramebuffer());
else
// write to default's framebuffer
glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE);
if (newFrame)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable (GL_BLEND); glDisable (GL_BLEND);
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
// do not use any shader // do not use any shader
@ -324,10 +296,6 @@ void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_
// write the framebuffer as is to the screen // write the framebuffer as is to the screen
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glDrawArrays (GL_TRIANGLES, 0, 6); glDrawArrays (GL_TRIANGLES, 0, 6);
// Get FB data from OpenGL, X11 will free this pointer when it is created into an XImage.
if (image_data)
glReadPixels(0, 0, 1920, 1080, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(image_data));
} }
void CWallpaper::setupFramebuffers () void CWallpaper::setupFramebuffers ()

View File

@ -31,7 +31,7 @@ namespace WallpaperEngine::Render
/** /**
* Performs a render pass of the wallpaper * Performs a render pass of the wallpaper
*/ */
void render (glm::vec4 viewport, bool drawToBackground = false, char* image_data = nullptr); void render (glm::ivec4 viewport, bool renderFrame = true, bool newFrame = true);
/** /**
* @return The container to resolve files for this wallpaper * @return The container to resolve files for this wallpaper
@ -71,11 +71,22 @@ namespace WallpaperEngine::Render
*/ */
CFBO* getFBO () const; CFBO* getFBO () const;
/**
* Updates the texcoord used for drawing to the used framebuffer
*/
void updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const;
/**
* Updates the destination framebuffer for this wallpaper
*
* @param framebuffer
*/
void setDestinationFramebuffer (GLuint framebuffer);
protected: protected:
/** /**
* Renders a frame of the wallpaper * Renders a frame of the wallpaper
*/ */
virtual void renderFrame (glm::vec4 viewport) = 0; virtual void renderFrame (glm::ivec4 viewport) = 0;
/** /**
* Setups OpenGL's framebuffers for ping-pong and scene rendering * Setups OpenGL's framebuffers for ping-pong and scene rendering
@ -108,6 +119,10 @@ namespace WallpaperEngine::Render
GLint g_Texture0; GLint g_Texture0;
GLint a_Position; GLint a_Position;
GLint a_TexCoord; GLint a_TexCoord;
/**
* The framebuffer to draw the background to
*/
GLuint m_destFramebuffer;
/** /**
* Setups OpenGL's shaders for this wallpaper backbuffer * Setups OpenGL's shaders for this wallpaper backbuffer
*/ */