[Feat] (EGL): support Linux X11 + EGL

This commit is contained in:
2026-06-07 08:21:20 +08:00
parent a15a13ca46
commit ff41e59282
12 changed files with 527 additions and 107 deletions
+177 -10
View File
@@ -14,6 +14,7 @@ namespace MobileGL {
namespace {
constexpr EGLint EGL_DISPLAY_MAJOR_VERSION = 1;
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
constexpr EGLint DEFAULT_MAX_PBUFFER_SIZE = 16384;
template <typename AttrType>
Optional<AttrType> ParseAttribValue(const AttrType* attribList, EGLint attrib) {
@@ -27,6 +28,55 @@ namespace MobileGL {
}
return Nullopt;
}
EGLint QueryDefaultX11VisualId() {
#if defined(__linux__) && !defined(__ANDROID__)
const char* displayName = std::getenv("DISPLAY");
if (!displayName) {
return 0;
}
void* x11Lib = dlopen("libX11.so.6", RTLD_LOCAL | RTLD_NOW);
if (!x11Lib) {
x11Lib = dlopen("libX11.so", RTLD_LOCAL | RTLD_NOW);
}
if (!x11Lib) {
return 0;
}
using XOpenDisplayFn = void* (*)(const char*);
using XDefaultScreenFn = int (*)(void*);
using XDefaultVisualFn = void* (*)(void*, int);
using XVisualIDFromVisualFn = unsigned long (*)(void*);
using XCloseDisplayFn = int (*)(void*);
auto* xOpenDisplay = reinterpret_cast<XOpenDisplayFn>(dlsym(x11Lib, "XOpenDisplay"));
auto* xDefaultScreen = reinterpret_cast<XDefaultScreenFn>(dlsym(x11Lib, "XDefaultScreen"));
auto* xDefaultVisual = reinterpret_cast<XDefaultVisualFn>(dlsym(x11Lib, "XDefaultVisual"));
auto* xVisualIDFromVisual =
reinterpret_cast<XVisualIDFromVisualFn>(dlsym(x11Lib, "XVisualIDFromVisual"));
auto* xCloseDisplay = reinterpret_cast<XCloseDisplayFn>(dlsym(x11Lib, "XCloseDisplay"));
if (!xOpenDisplay || !xDefaultScreen || !xDefaultVisual || !xVisualIDFromVisual || !xCloseDisplay) {
dlclose(x11Lib);
return 0;
}
void* display = xOpenDisplay(displayName);
if (!display) {
dlclose(x11Lib);
return 0;
}
const int screen = xDefaultScreen(display);
void* visual = xDefaultVisual(display, screen);
const auto visualId = visual ? static_cast<EGLint>(xVisualIDFromVisual(visual)) : 0;
xCloseDisplay(display);
dlclose(x11Lib);
return visualId;
#else
return 0;
#endif
}
} // namespace
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
@@ -99,30 +149,31 @@ namespace MobileGL {
.SwapInterval = 1,
};
const auto config = CreateDefaultConfig(display);
displayObject.Configs.push_back(config);
displayObject.Configs.push_back(CreateDefaultConfig(display, 1, 0));
displayObject.Configs.push_back(CreateDefaultConfig(display, 2, 8));
m_displays[display] = displayObject;
m_displayLookup[key] = display;
return display;
}
EGLContext::EGLConfigHandle EGLContext::CreateDefaultConfig(EGLDisplayHandle display) {
EGLContext::EGLConfigHandle EGLContext::CreateDefaultConfig(EGLDisplayHandle display, EGLint configId,
EGLint stencilSize) {
const auto config = EncodeHandle<EGLConfigHandle>(m_nextConfigHandle++);
ConfigObject cfg = {
.Display = display,
.ConfigId = 1,
.ConfigId = configId,
.RedSize = 8,
.GreenSize = 8,
.BlueSize = 8,
.AlphaSize = 8,
.DepthSize = 24,
.StencilSize = 8,
.StencilSize = stencilSize,
.SurfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_PIXMAP_BIT,
.RenderableType = EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT,
.MinSwapInterval = 0,
.MaxSwapInterval = 4,
.NativeVisualId = 0,
.NativeVisualId = QueryDefaultX11VisualId(),
};
#if defined(ANDROID) || defined(__ANDROID__)
cfg.NativeVisualId = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
@@ -294,7 +345,6 @@ namespace MobileGL {
Bool EGLContext::ChooseConfig(EGLDisplayHandle display, const EGLint* attribList, EGLConfigHandle* configs,
EGLint configSize, EGLint* numConfig) {
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
(void)attribList;
auto* displayObject = TryGetDisplay(display);
if (!displayObject) {
SetError(EGL_BAD_DISPLAY);
@@ -309,14 +359,84 @@ namespace MobileGL {
return false;
}
*numConfig = static_cast<EGLint>(displayObject->Configs.size());
Vector<EGLConfigHandle> matchedConfigs;
for (const auto config : displayObject->Configs) {
const auto* cfg = TryGetConfig(config);
if (!cfg) {
continue;
}
Bool matches = true;
if (attribList) {
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
const EGLint attr = attribList[i];
const EGLint requested = attribList[i + 1];
if (requested == EGL_DONT_CARE) {
continue;
}
switch (attr) {
case EGL_CONFIG_ID:
matches = cfg->ConfigId == requested;
break;
case EGL_RED_SIZE:
matches = cfg->RedSize >= requested;
break;
case EGL_GREEN_SIZE:
matches = cfg->GreenSize >= requested;
break;
case EGL_BLUE_SIZE:
matches = cfg->BlueSize >= requested;
break;
case EGL_ALPHA_SIZE:
matches = cfg->AlphaSize >= requested;
break;
case EGL_BUFFER_SIZE:
matches = (cfg->RedSize + cfg->GreenSize + cfg->BlueSize + cfg->AlphaSize) >= requested;
break;
case EGL_DEPTH_SIZE:
matches = cfg->DepthSize >= requested;
break;
case EGL_STENCIL_SIZE:
matches = cfg->StencilSize >= requested;
break;
case EGL_SURFACE_TYPE:
matches = (cfg->SurfaceType & requested) == requested;
break;
case EGL_RENDERABLE_TYPE:
case EGL_CONFORMANT:
matches = (cfg->RenderableType & requested) == requested;
break;
case EGL_SAMPLE_BUFFERS:
case EGL_SAMPLES:
matches = requested == 0;
break;
case EGL_NATIVE_VISUAL_ID:
matches = cfg->NativeVisualId == requested;
break;
default:
break;
}
if (!matches) {
break;
}
}
}
if (matches) {
matchedConfigs.push_back(config);
}
}
*numConfig = static_cast<EGLint>(matchedConfigs.size());
if (!configs || configSize <= 0) {
return true;
}
const SizeT copyCount = std::min(static_cast<SizeT>(configSize), displayObject->Configs.size());
const SizeT copyCount = std::min(static_cast<SizeT>(configSize), matchedConfigs.size());
for (SizeT i = 0; i < copyCount; ++i) {
configs[i] = displayObject->Configs[i];
configs[i] = matchedConfigs[i];
}
return true;
}
@@ -356,9 +476,38 @@ namespace MobileGL {
}
switch (attribute) {
case EGL_BUFFER_SIZE:
*value = cfg->RedSize + cfg->GreenSize + cfg->BlueSize + cfg->AlphaSize;
return true;
case EGL_ALPHA_MASK_SIZE:
*value = 0;
return true;
case EGL_BIND_TO_TEXTURE_RGB:
case EGL_BIND_TO_TEXTURE_RGBA:
*value = EGL_FALSE;
return true;
case EGL_COLOR_BUFFER_TYPE:
*value = EGL_RGB_BUFFER;
return true;
case EGL_CONFIG_CAVEAT:
*value = EGL_NONE;
return true;
case EGL_CONFIG_ID:
*value = cfg->ConfigId;
return true;
case EGL_LEVEL:
*value = 0;
return true;
case EGL_LUMINANCE_SIZE:
*value = 0;
return true;
case EGL_MAX_PBUFFER_WIDTH:
case EGL_MAX_PBUFFER_HEIGHT:
*value = DEFAULT_MAX_PBUFFER_SIZE;
return true;
case EGL_MAX_PBUFFER_PIXELS:
*value = DEFAULT_MAX_PBUFFER_SIZE * DEFAULT_MAX_PBUFFER_SIZE;
return true;
case EGL_RED_SIZE:
*value = cfg->RedSize;
return true;
@@ -390,9 +539,27 @@ namespace MobileGL {
case EGL_MAX_SWAP_INTERVAL:
*value = cfg->MaxSwapInterval;
return true;
case EGL_NATIVE_RENDERABLE:
*value = EGL_TRUE;
return true;
case EGL_NATIVE_VISUAL_ID:
*value = cfg->NativeVisualId;
return true;
case EGL_NATIVE_VISUAL_TYPE:
*value = cfg->NativeVisualId;
return true;
case EGL_SAMPLE_BUFFERS:
case EGL_SAMPLES:
*value = 0;
return true;
case EGL_TRANSPARENT_TYPE:
*value = EGL_NONE;
return true;
case EGL_TRANSPARENT_RED_VALUE:
case EGL_TRANSPARENT_GREEN_VALUE:
case EGL_TRANSPARENT_BLUE_VALUE:
*value = 0;
return true;
default:
const_cast<EGLContext*>(this)->SetError(EGL_BAD_ATTRIBUTE);
return false;
+1 -1
View File
@@ -213,7 +213,7 @@ namespace MobileGL {
static std::thread::id CurrentThreadKey();
EGLDisplayHandle GetOrCreateDisplay(Uint64 nativeDisplayKey, EGLenum platform);
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display);
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display, EGLint configId, EGLint stencilSize);
DisplayObject* TryGetDisplay(EGLDisplayHandle display);
const DisplayObject* TryGetDisplay(EGLDisplayHandle display) const;