From 551624d89ac272ef91d99c6c51c6579adadbf5c5 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 12 Dec 2015 14:14:51 +0200 Subject: [PATCH] Render each monitor separately --- Makefile | 2 +- source/main.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 181 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index db9a8f8..aa04a2b 100644 --- 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 diff --git a/source/main.c b/source/main.c index c0bbe0e..f34acb5 100644 --- a/source/main.c +++ b/source/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -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; y0) + 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; inmonitors; ++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; inwindows; ++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; inmonitors; ++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; -- 2.45.2