Selaa lähdekoodia

Fixed issue #59 for Nvidia graphics cards and added compositor support (#75)

* Fixes issue #59's origial issue

* Hide GLFW for X Render

* Enable compositor support

* Added signal handling if the user terminates the program

* Fixed issue with screens not at 0, 0 not rendering. Also cleaned up.

* Consolidated the renderImage function into render.

* Moved display, pm, and gc to class members.

* Fixed memory leak due to forgetting to move initializer code.

* Revert changes due to introducting flickering.
Hynak 4 vuotta sitten
vanhempi
commit
a9db3ff364

+ 36 - 0
main.cpp

@@ -8,8 +8,12 @@
 #include <GL/glew.h>
 #include <GL/glx.h>
 #include <filesystem>
+#include <csignal>
 #include "GLFW/glfw3.h"
 
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
 #include "WallpaperEngine/Core/CProject.h"
 #include "WallpaperEngine/Render/CWallpaper.h"
 #include "WallpaperEngine/Render/CContext.h"
@@ -54,6 +58,26 @@ std::string stringPathFixes(const std::string& s)
     return std::move (str);
 }
 
+void free_display_wallpaper(int sig)
+{
+    Display* display = XOpenDisplay (nullptr);
+    Window root = DefaultRootWindow(display);
+    // create a blank pm to reset compositors values, compositors will render as a blank X window.
+    Pixmap pm = XCreatePixmap(display, root, 1, 1, 1);
+    Atom prop_root = XInternAtom(display, "_XROOTPMAP_ID", False);
+    Atom prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
+    XChangeProperty(display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
+    XChangeProperty(display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
+    XFreePixmap(display, pm);
+    // set background to black. Only needed if no compositors are running
+    XSetWindowBackground(display, root, 0);
+    // sync changes before exiting
+    XClearWindow(display, root);
+    XFlush(display);
+    XCloseDisplay(display);
+    exit(sig);
+}
+
 int main (int argc, char* argv[])
 {
     std::vector <std::string> screens;
@@ -145,6 +169,14 @@ int main (int argc, char* argv[])
 
     // ensure the path has a trailing slash
 
+    // Attach signals for unexpected killing of program by user. We need to reset the 
+    // screen otherwise the background will remain the last frame on sigterm or sigint.
+    if (!screens.empty())
+    {
+        std::signal(SIGINT, free_display_wallpaper);
+        std::signal(SIGTERM, free_display_wallpaper);
+    }
+
     // first of all, initialize the window
     if (glfwInit () == GLFW_FALSE)
     {
@@ -160,6 +192,10 @@ int main (int argc, char* argv[])
     glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 2);
     glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 1);
 
+    // will hide the window if we are drawing to X
+    if (!screens.empty())
+        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
+
     auto containers = new WallpaperEngine::Assets::CCombinedContainer ();
 
     // update the used path with the full one

+ 34 - 9
src/WallpaperEngine/Render/CContext.cpp

@@ -1,5 +1,6 @@
 #include <iostream>
 #include <X11/Xlib.h>
+#include <X11/Xatom.h>
 #include <X11/extensions/Xrandr.h>
 
 #include <GL/glew.h>
@@ -76,8 +77,8 @@ void CContext::initializeViewports ()
 
     XRRFreeScreenResources (screenResources);
 
-    // set the
-    glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display)));
+    // Cause of issue for issue #59 origial issue
+    // glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display)));
 }
 
 void CContext::render ()
@@ -87,19 +88,43 @@ void CContext::render ()
 
     if (this->m_viewports.empty () == false)
     {
-        bool firstFrame = true;
-        bool renderFrame = true;
+        static Display* display = XOpenDisplay (nullptr);
         auto cur = this->m_viewports.begin ();
         auto end = this->m_viewports.end ();
 
+        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 ++)
         {
-            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> ();
+            XPutImage(display, pm, gc, image, 0, 0, (*cur).x, (*cur).y, windowWidth, windowHeight);
         }
+
+        // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to 
+        // edit the background. Without these, other programs will clear the screen.
+        Atom prop_root = XInternAtom(display, "_XROOTPMAP_ID", False);
+        Atom prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
+        XChangeProperty(display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
+        XChangeProperty(display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
+
+        XSetWindowBackgroundPixmap(display, root, pm);
+        XClearWindow(display, root);
+        XFlush(display);
+
+        XDestroyImage(image);
+        XFreePixmap(display, pm);
+        XFreeGC(display, gc);
     }
     else
         this->m_wallpaper->render (this->m_defaultViewport);

+ 51 - 8
src/WallpaperEngine/Render/CWallpaper.cpp

@@ -185,10 +185,9 @@ void CWallpaper::setupShaders ()
     this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
 }
 
-void CWallpaper::render (glm::vec4 viewport, bool renderFrame, bool newFrame)
+void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_data)
 {
-    if (renderFrame == true)
-        this->renderFrame (viewport);
+    this->renderFrame (viewport);
 
     int windowWidth = 1920;
     int windowHeight = 1080;
@@ -258,13 +257,53 @@ void CWallpaper::render (glm::vec4 viewport, bool renderFrame, bool newFrame)
     glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
     glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
 
-    glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
+    // 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);
+        }
+    }
 
-    // write to default's framebuffer
-    glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE);
+    glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
 
-    if (newFrame == true)
-        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    static CFBO* screen_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
+    
+    if (drawToBackground)
+        // write to screen buffer
+        glBindFramebuffer (GL_FRAMEBUFFER, screen_fbo->getFramebuffer());
+    else
+        // write to default's framebuffer
+        glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE);
+
+    
+    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glDisable (GL_BLEND);
     glDisable (GL_DEPTH_TEST);
     // do not use any shader
@@ -285,6 +324,10 @@ void CWallpaper::render (glm::vec4 viewport, bool renderFrame, bool newFrame)
     // write the framebuffer as is to the screen
     glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
     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 ()

+ 1 - 1
src/WallpaperEngine/Render/CWallpaper.h

@@ -31,7 +31,7 @@ namespace WallpaperEngine::Render
         /**
          * Performs a render pass of the wallpaper
          */
-        void render (glm::vec4 viewport, bool renderFrame = true, bool newFrame = true);
+        void render (glm::vec4 viewport, bool drawToBackground = false, char* image_data = nullptr);
 
         /**
          * @return The container to resolve files for this wallpaper