#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>
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;
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;
" 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,
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);
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)));
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;
}
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;
int x, y;
unsigned border;
unsigned depth;
+ XRRScreenResources *xrr_res;
Window dummy_parent;
Window *children;
unsigned nchildren;
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));
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");
XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
free(screen->windows);
+ free(screen->monitors);
}
void shutdown_compositor(Compositor *compositor)
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];
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;