Skip to content

Commit

Permalink
finally support EGL transparency under X11
Browse files Browse the repository at this point in the history
  • Loading branch information
nullgemm committed May 14, 2024
1 parent fcd89a4 commit 3eccc34
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 25 deletions.
1 change: 0 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ X11
- `software` provides CPU and GPU buffers using XCB's SHM module.
- `vulkan` provides Vulkan contexts using Vulkan's WSI XCB support.
- `egl` provides OpenGL contexts using XCB, EGL and libX11 when required.
Transparent contexts are not supported yet because of a bug in EGL.
- `glx` provides OpenGL contexts using XCB, GLX and libX11 when required.

Windows (background blur is not supported since it requires using private APIs)
Expand Down
166 changes: 143 additions & 23 deletions src/x11/x11_egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <stdlib.h>
#include <xcb/xcb.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

void globox_x11_egl_init(
struct globox* context,
Expand Down Expand Up @@ -101,14 +102,6 @@ void globox_x11_egl_window_create(
return;
}

// run common X11 helper
globox_x11_common_window_create(context, platform, configs, count, callback, data, error);

if (globox_error_get_code(error) != GLOBOX_ERROR_OK)
{
return;
}

// get display
backend->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

Expand Down Expand Up @@ -144,27 +137,147 @@ void globox_x11_egl_window_create(
return;
}

// get egl config count
EGLint attr_configs_alloc_size = 0;
EGLint attr_configs_fill_size = 0;
EGLConfig* attr_configs = NULL;

error_egl =
eglChooseConfig(
backend->display,
backend->config->attributes,
&(backend->attr_config),
1,
&(backend->attr_config_size));
NULL,
0,
&attr_configs_alloc_size);

if ((error_egl == EGL_FALSE) || (attr_configs_alloc_size == 0))
{
globox_error_throw(context, error, GLOBOX_ERROR_X11_EGL_CONFIG);
return;
}

// allocate config array
attr_configs = malloc((sizeof (EGLConfig)) * attr_configs_alloc_size);

if (attr_configs == NULL)
{
globox_error_throw(context, error, GLOBOX_ERROR_ALLOC);
return;
}

// get egl configs
error_egl =
eglChooseConfig(
backend->display,
backend->config->attributes,
attr_configs,
attr_configs_alloc_size,
&attr_configs_fill_size);

if (error_egl == EGL_FALSE)
{
globox_error_throw(context, error, GLOBOX_ERROR_X11_EGL_CONFIG);
free(attr_configs);
return;
}

// check if the egl config groups extension is available
bool group_ext = false;

#ifdef EGL_EXT_config_select_group
const char* list =
eglQueryString(
backend->display,
EGL_EXTENSIONS);

group_ext =
x11_helpers_egl_ext_support(
list,
"EGL_EXT_config_select_group");
#endif

if (group_ext == false)
{
context->feature_background->background = GLOBOX_BACKGROUND_OPAQUE;
}

// find compatible visual
EGLint attr_context[] =
{
EGL_CONTEXT_MAJOR_VERSION, backend->config->major_version,
EGL_CONTEXT_MINOR_VERSION, backend->config->minor_version,
EGL_NONE,
};

EGLint i = 0;

while (i < attr_configs_fill_size)
{
// get visual depth from EGL
EGLint visual_depth;

error_egl =
eglGetConfigAttrib(
backend->display,
attr_configs[i],
EGL_DEPTH_SIZE,
&visual_depth);

if (error_egl == EGL_FALSE)
{
globox_error_throw(context, error, GLOBOX_ERROR_X11_EGL_CONFIG_ATTR);
free(attr_configs);
return;
}

// break if creating an opaque context
if (context->feature_background->background == GLOBOX_BACKGROUND_OPAQUE)
{
platform->visual_depth = visual_depth;
break;
}

// get transparency info from EGL
EGLint group;

error_egl =
eglGetConfigAttrib(
backend->display,
attr_configs[i],
EGL_CONFIG_SELECT_GROUP_EXT,
&group);

if (error_egl == EGL_FALSE)
{
globox_error_throw(context, error, GLOBOX_ERROR_X11_EGL_CONFIG_ATTR);
free(attr_configs);
return;
}

// break if visual supports transparency
if ((group == 1) && (visual_depth == 24))
{
platform->visual_depth = 32;
break;
}

// continue searching for a compatible context
++i;
}

// since X11 EGL transparency support was only added recently,
// fall back to using opaque contexts if needed...
if (i == attr_configs_fill_size)
{
context->feature_background->background = GLOBOX_BACKGROUND_OPAQUE;
i = 0;
}

// save config and free array
backend->attr_config = attr_configs[i];
free(attr_configs);

// create context
backend->egl =
eglCreateContext(
backend->display,
Expand Down Expand Up @@ -196,24 +309,31 @@ void globox_x11_egl_window_create(

platform->visual_id = visual_id;

// get visual depth from EGL
EGLint visual_depth;
if (context->feature_background->background != GLOBOX_BACKGROUND_OPAQUE)
{
// generate a compatible colormap for the chosen visual id
xcb_colormap_t colormap =
xcb_generate_id(
platform->conn);

xcb_create_colormap(
platform->conn,
XCB_COLORMAP_ALLOC_NONE,
colormap,
platform->screen_obj->root,
platform->visual_id);

platform->attr_val[2] = colormap;
}

error_egl =
eglGetConfigAttrib(
backend->display,
backend->attr_config,
EGL_DEPTH_SIZE,
&visual_depth);
// run common X11 helper
globox_x11_common_window_create(context, platform, configs, count, callback, data, error);

if (error_egl == EGL_FALSE)
if (globox_error_get_code(error) != GLOBOX_ERROR_OK)
{
globox_error_throw(context, error, GLOBOX_ERROR_X11_EGL_CONFIG_ATTR);
return;
}

platform->visual_depth = visual_depth;

// unlock mutex
error_posix = pthread_mutex_unlock(&(platform->mutex_main));

Expand Down
27 changes: 27 additions & 0 deletions src/x11/x11_egl_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@
#include <string.h>
#include <EGL/egl.h>

bool x11_helpers_egl_ext_support(const char *list, const char *extension)
{
const char* beg = list;
const char* end;
const char* cur;

cur = strstr(beg, extension);

while (cur != NULL)
{
end = cur + strlen(extension);

// the extension name might be a subset of another one so
// we must check the surrouding characters to make sure
if (((cur == beg) || (cur[-1] == ' '))
&& ((end[0] == '\0') || (end[0] == ' ')))
{
return true;
}

beg = end;
cur = strstr(beg, extension);
}

return false;
}

void x11_helpers_egl_bind(struct globox* context, struct globox_error_info* error)
{
struct x11_egl_backend* backend = context->backend_data;
Expand Down
5 changes: 4 additions & 1 deletion src/x11/x11_egl_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ struct x11_egl_backend
EGLDisplay display;
EGLSurface surface;
EGLConfig attr_config;
EGLint attr_config_size;
};

bool x11_helpers_egl_ext_support(
const char *list,
const char *extension);

void x11_helpers_egl_bind(
struct globox* context,
struct globox_error_info* error);
Expand Down
1 change: 1 addition & 0 deletions src/x11/x11_glx.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ void globox_x11_glx_window_create(
continue;
}

// TODO clarify validity matching code
fb_valid = true;
backend->fb_config = fb_config_list[i];

Expand Down

0 comments on commit 3eccc34

Please sign in to comment.