The following code (a bare minimal example) produces a triangle on top of a plain color screen. The triangle and the screen colors have alpha values of 1.0, but still when the program is run with compositor enabled (X11/KDE system settings) the colors are merged with whatever is behind the window. The effect produced is like the window have an opacity setting (except for the titlebar, so it is not the window opacity value).
I tried my best to avoid this behavior, changing X Visuals, changing Egl configurations, Depths, disabling opengl blending, changing blending functions, etc... The only way I found to prevent it is to change the visuals to 24bits, but then It doesn't compose anymore, and I want the composition, as I want some parts of the output to be blended but not everything and without control.
Here is a minimal reproducible example:
//
//compilation example: g++ test.cpp -o test -lEGL -lX11 -lGLX -lOpenGL
//
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <EGL/egl.h>
const char *vertexShaderSource=
"#version 330 core\n"
"layout (location=0) in vec3 aPos;\n"
"void main(){gl_Position = vec4 (aPos.x,aPos.y,aPos.z,1.0);}"
;
const char *fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main(){FragColor = vec4 (1.0,0.5f,0.2f,1.0f);}"
;
float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f };
GLuint load_shader ( const char *shader_source, GLenum type )
{
GLuint shader = glCreateShader( type );
glShaderSource ( shader , 1 , &shader_source , nullptr );
glCompileShader ( shader );
return shader;
}
bool someerror=false;
template<typename T>
T &showError(const char * err,T&t)
{
if (!t)
{
someerror=true;
std::cerr<<err<<std::endl;
}
return t;
}
template<typename T>
const T &showError(const char * err,const T&t)
{
if (!t)
{
someerror=true;
std::cerr<<err<<std::endl;
}
return t;
}
int main(int, char**)
{
auto display=XOpenDisplay(nullptr);
showError("Error opening display",display);
auto egl_display=eglGetDisplay(EGL_CAST(EGLNativeDisplayType,display));
showError("Error opening egl display",egl_display);
showError("Error initializing egl",eglInitialize(egl_display,nullptr,nullptr));
showError("Error binding api",eglBindAPI(EGL_OPENGL_API));
auto screen=DefaultScreen(display);
Window parentWin=RootWindow(display,screen);
XVisualInfo vinfo;
Window win;
XSetWindowAttributes setWAtt;
//
// Change UseDepth=24 to avoid compositor at all
//
auto UseDepth=32;
if (!XMatchVisualInfo(display, screen, UseDepth, TrueColor, &vinfo))
{
win=XCreateWindow(display,parentWin,0,0,800,480,0,CopyFromParent,InputOutput,CopyFromParent,0,nullptr);
}
else
{
setWAtt.colormap = XCreateColormap(display, parentWin, vinfo.visual, AllocNone);
setWAtt.background_pixel = 0xffffffff;
setWAtt.border_pixel = 0xffffffff;
auto valueMask=CWColormap|CWBorderPixel|CWBackPixel;
win=XCreateWindow(display,parentWin,0,0,800,480,0,vinfo.depth, InputOutput, vinfo.visual,valueMask,&setWAtt);
}
showError("Error creating window",win);
XWMHints hints;
hints.input = true;
hints.flags = InputHint;
XSetWMHints(display, win, &hints);
XMapWindow ( display , win );
XSync(display,false);
EGLint attr[] = {EGL_RED_SIZE,8,EGL_GREEN_SIZE,8,EGL_BLUE_SIZE,8,EGL_NONE};
EGLConfig ecfg[200];
EGLint num_config;
showError("Error choosing egl config",eglChooseConfig( egl_display, attr, ecfg, 200, &num_config ));
EGLSurface egl_surface;
int matchConfig=0;
for (;matchConfig<num_config;matchConfig++)
{
egl_surface = eglCreateWindowSurface ( egl_display, ecfg[matchConfig], win, nullptr );
if ( egl_surface)
break;
}
showError("Error creating surface",egl_surface);
EGLint ctxattr[] = { EGL_NONE };
auto egl_context = eglCreateContext ( egl_display, ecfg[matchConfig], EGL_NO_CONTEXT, ctxattr );
showError("Error creating context",egl_context);
eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );
GLuint vertexShader = load_shader ( vertexShaderSource , GL_VERTEX_SHADER );
GLuint fragmentShader = load_shader ( fragmentShaderSource , GL_FRAGMENT_SHADER );
GLuint shaderProgram = glCreateProgram ();
glAttachShader ( shaderProgram, fragmentShader );
glAttachShader ( shaderProgram, vertexShader );
glLinkProgram ( shaderProgram );
glUseProgram ( shaderProgram );
while (!someerror)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glVertexAttribPointer ( 0, 3, GL_FLOAT, false, 0, vertices );
glEnableVertexAttribArray ( 0 );
glDrawArrays(GL_TRIANGLES,0,3);
eglSwapBuffers ( egl_display, egl_surface );
}
return 0;
}
The output produced, at left with compositor enabled, at right without:
My goal is to produce something like this with compositor enabled:
My testing platform:
- OpenSuse Tumbleweed 20201018
- KDE/Plasma 5.19.5
- GeForce RTX 2070 SUPER (with nvidia drivers)
- Xorg server 1.20.9
- Kernel 5.8.14

