]> git.tdb.fi Git - geometrycompositor.git/commitdiff
Render each monitor separately
authorMikko Rasa <tdb@tdb.fi>
Sat, 12 Dec 2015 12:14:51 +0000 (14:14 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 12 Dec 2015 12:17:51 +0000 (14:17 +0200)
Makefile
source/main.c

index db9a8f80ddece2417fa232927502fc8e001e062c..aa04a2b52f39313649a3dfa688fea8ee09bf3d15 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,2 +1,2 @@
 geometrycompositor: source/main.c
-       gcc -o $@ $< -Wall -Wextra -Werror -std=c90 -pedantic -ggdb -lX11 -lXcomposite -lXdamage -lXext -lGL
+       gcc -o $@ $< -Wall -Wextra -Werror -std=c90 -pedantic -ggdb -lX11 -lXcomposite -lXdamage -lXext -lXrandr -lGL
index c0bbe0e20c8d0d711242216e36a706d4b013eb8e..f34acb54885ac30a1e1d5ea18869f6aba83f5151 100644 (file)
@@ -7,6 +7,7 @@
 #include <X11/extensions/Xcomposite.h>
 #include <X11/extensions/Xdamage.h>
 #include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
 #include <GL/gl.h>
 #include <GL/glx.h>
 
@@ -25,6 +26,20 @@ typedef struct CompositedWindow
        unsigned texture;
 } CompositedWindow;
 
+typedef struct CompositedMonitor
+{
+       int enabled;
+       int x;
+       int y;
+       unsigned width;
+       unsigned height;
+       unsigned vertex_buffer;
+       unsigned index_buffer;
+       unsigned vertex_array;
+       unsigned tessellation;
+       unsigned nelements;
+} CompositedMonitor;
+
 typedef struct CompositedScreen
 { 
        int number;
@@ -39,11 +54,15 @@ typedef struct CompositedScreen
        unsigned shaders[2];
        unsigned program;
        unsigned geometry_loc;
-       unsigned vertex_buffer;
-       unsigned vertex_array;
+       unsigned window_vertex_buffer;
+       unsigned window_vertex_array;
+       unsigned framebuffer;
+       unsigned fb_texture;
        CompositedWindow *windows;
        unsigned nwindows;
        unsigned windows_capacity;
+       CompositedMonitor *monitors;
+       unsigned nmonitors;
        int dirty;
 } CompositedScreen;
 
@@ -81,7 +100,7 @@ static const char *fshader =
        "       frag_color = texture(image, texcoord);\n"
        "}\n";
 
-static const float vertices[] =
+static const float window_vertices[] =
 {
        /* vertex    texcoord */
        0.0f, 1.0f,  0.0f, 0.0f,
@@ -144,7 +163,7 @@ int initialize_gl(Compositor *compositor, CompositedScreen *screen)
        attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
        attribs[i++] = 3;
        attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
-       attribs[i++] = 0;
+       attribs[i++] = 1;
        attribs[i] = None;
 
        screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
@@ -230,13 +249,13 @@ int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
 
        screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
 
-       glGenBuffers(1, &screen->vertex_buffer);
-       glBindBuffer(GL_ARRAY_BUFFER, screen->vertex_buffer);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+       glGenBuffers(1, &screen->window_vertex_buffer);
+       glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
 
        stride = 4*sizeof(float);
-       glGenVertexArrays(1, &screen->vertex_array);
-       glBindVertexArray(screen->vertex_array);
+       glGenVertexArrays(1, &screen->window_vertex_array);
+       glBindVertexArray(screen->window_vertex_array);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
@@ -245,6 +264,20 @@ int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
 
        glBindBuffer(GL_ARRAY_BUFFER, 0);
 
+       glGenTextures(1, &screen->fb_texture);
+       glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       glBindTexture(GL_TEXTURE_2D, 0);
+
+       glGenFramebuffers(1, &screen->framebuffer);
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
+       glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
+       glDepthMask(GL_FALSE);
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
        return 1;
 }
 
@@ -414,6 +447,103 @@ CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
        return NULL;
 }
 
+void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
+{
+       unsigned t;
+       unsigned data_size;
+       float *vertex_data;
+       unsigned short *index_data;
+       unsigned x, y;
+       unsigned i;
+
+       t = monitor->tessellation;
+
+       data_size = (t+1)*(t+1)*4*sizeof(float);
+       vertex_data = (float *)malloc(data_size);
+       for(y=0; y<=t; ++y)
+               for(x=0; x<=t; ++x)
+               {
+                       float xf, yf;
+                       float *v;
+
+                       xf = (float)x/t;
+                       yf = (float)y/t;
+                       v = vertex_data+(y*(t+1)+x)*4;
+                       v[0] = xf;
+                       v[1] = yf;
+                       v[2] = (monitor->x+xf*monitor->width)/screen->width;
+                       v[3] = (monitor->y+yf*monitor->height)/screen->height;
+               }
+       glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
+       glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
+       glBindBuffer(GL_ARRAY_BUFFER, 0);
+       free(vertex_data);
+
+       monitor->nelements = t*((t+1)*2+1)-1;
+       data_size = monitor->nelements*sizeof(unsigned short);
+       index_data = (unsigned short *)malloc(data_size);
+       i = 0;
+       for(y=0; y<t; ++y)
+       {
+               if(y>0)
+                       index_data[i++] = 0xFFFF;
+               for(x=0; x<=t; ++x)
+               {
+                       index_data[i++] = (y+1)*(t+1)+x;
+                       index_data[i++] = y*(t+1)+x;
+               }
+       }
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
+       glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+       free(index_data);
+}
+
+int initialize_monitor(Compositor *compositor, CompositedScreen *screen, CompositedMonitor *monitor, XRRScreenResources *xrr_res, unsigned index)
+{
+       XRROutputInfo *output;
+       XRRCrtcInfo *crtc;
+       unsigned buffers[2];
+       unsigned stride;
+
+       output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
+       monitor->enabled = !!output->crtc;
+       if(!monitor->enabled)
+       {
+               XRRFreeOutputInfo(output);
+               return 1;
+       }
+
+       crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
+       monitor->x = crtc->x;
+       monitor->y = crtc->y;
+       monitor->width = crtc->width;
+       monitor->height = crtc->height;
+       XRRFreeCrtcInfo(crtc);
+       XRRFreeOutputInfo(output);
+
+       glGenBuffers(2, buffers);
+       monitor->vertex_buffer = buffers[0];
+       monitor->index_buffer = buffers[1];
+
+       monitor->tessellation = 20;
+       update_monitor_vertices(screen, monitor);
+       stride = 4*sizeof(float);
+
+       glGenVertexArrays(1, &monitor->vertex_array);
+       glBindVertexArray(monitor->vertex_array);
+       glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
+       glEnableVertexAttribArray(1);
+       glBindBuffer(GL_ARRAY_BUFFER, 0);
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
+       glBindVertexArray(0);
+
+       return 1;
+}
+
 int initialize_screen(Compositor *compositor, unsigned number)
 {
        CompositedScreen *screen;
@@ -422,6 +552,7 @@ int initialize_screen(Compositor *compositor, unsigned number)
        int x, y;
        unsigned border;
        unsigned depth;
+       XRRScreenResources *xrr_res;
        Window dummy_parent;
        Window *children;
        unsigned nchildren;
@@ -448,6 +579,14 @@ int initialize_screen(Compositor *compositor, unsigned number)
        if(!create_gl_resources(compositor, screen))
                return 0;
 
+       xrr_res = XRRGetScreenResources(compositor->display, screen->root);
+       screen->nmonitors = xrr_res->noutput;
+       screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
+       for(i=0; i<screen->nmonitors; ++i)
+               if(!initialize_monitor(compositor, screen, &screen->monitors[i], xrr_res, i))
+                       return 0;
+       XRRFreeScreenResources(xrr_res);
+
        XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
 
        screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
@@ -506,6 +645,13 @@ int initialize_compositor(Compositor *compositor)
        else if(major_ver<1 || (major_ver==1 && minor_ver<1))
                return with_error("XShape 1.1 or later is required");
 
+       if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
+               return with_error("XRandR is required but was not found");
+       else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
+               return with_error("Cannot determine XRandR version");
+       else if(major_ver<1 || (major_ver==1 && minor_ver<2))
+               return with_error("XRandR 1.2 or later is required");
+
        compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
        compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
        compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
@@ -546,6 +692,7 @@ void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
        XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
 
        free(screen->windows);
+       free(screen->monitors);
 }
 
 void shutdown_compositor(Compositor *compositor)
@@ -731,11 +878,13 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen)
 
        use_gl(compositor, screen);
 
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
+
        glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
 
        glUseProgram(screen->program);
-       glBindVertexArray(screen->vertex_array);
+       glBindVertexArray(screen->window_vertex_array);
        for(i=0; i<screen->nwindows; ++i)
        {
                CompositedWindow *window = &screen->windows[i];
@@ -752,6 +901,27 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen)
                XDamageSubtract(compositor->display, window->damage, None, None);
        }
 
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+       glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
+       glClear(GL_COLOR_BUFFER_BIT);
+       glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
+       glEnable(GL_PRIMITIVE_RESTART);
+       glPrimitiveRestartIndex(0xFFFF);
+
+       for(i=0; i<screen->nmonitors; ++i)
+       {
+               CompositedMonitor *monitor = &screen->monitors[i];
+               if(!monitor->enabled)
+                       continue;
+
+               glUniform4f(screen->geometry_loc,
+                       (float)monitor->x/screen->width, (float)monitor->y/screen->height,
+                       (float)monitor->width/screen->width, (float)monitor->height/screen->height);
+
+               glBindVertexArray(monitor->vertex_array);
+               glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
+       }
+
        glXSwapBuffers(compositor->display, screen->glx_window);
 
        screen->dirty = 0;