mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (EGL): support Linux X11 + EGL
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ namespace MobileGL::MG_Backend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +64,35 @@ namespace MobileGL::MG_Backend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_eglWindowSurfaceInitialized = true;
|
m_eglSurfaceInitialized = true;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::Window;
|
||||||
|
m_eglCurrentThreads.clear();
|
||||||
|
m_backendCapabilitiesInitialized = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::CreateEGLPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_eglDisplayInitialized) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: EGL display is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: invalid size %dx%d", width, height);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InitPbufferSurface(width, height)) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: backend InitPbufferSurface failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eglSurfaceInitialized = true;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::Pbuffer;
|
||||||
m_eglCurrentThreads.clear();
|
m_eglCurrentThreads.clear();
|
||||||
m_backendCapabilitiesInitialized = false;
|
m_backendCapabilitiesInitialized = false;
|
||||||
return true;
|
return true;
|
||||||
@@ -81,8 +110,8 @@ namespace MobileGL::MG_Backend {
|
|||||||
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
|
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m_eglWindowSurfaceInitialized) {
|
if (!m_eglSurfaceInitialized) {
|
||||||
MGLOG_E("MakeEGLCurrent failed: EGL window surface is not initialized");
|
MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
|
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
|
||||||
@@ -104,8 +133,9 @@ namespace MobileGL::MG_Backend {
|
|||||||
|
|
||||||
void BackendObject::ResetEGLRuntimeState() {
|
void BackendObject::ResetEGLRuntimeState() {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
m_eglWindowSurfaceInitialized = false;
|
m_eglSurfaceInitialized = false;
|
||||||
m_backendCapabilitiesInitialized = false;
|
m_backendCapabilitiesInitialized = false;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::None;
|
||||||
m_eglCurrentThreads.clear();
|
m_eglCurrentThreads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +149,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
MGLOG_E("SwapEGLBuffers failed: no current context attached");
|
MGLOG_E("SwapEGLBuffers failed: no current context attached");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m_eglWindowSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
||||||
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
|
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -138,4 +168,10 @@ namespace MobileGL::MG_Backend {
|
|||||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
m_windowHandle = handle;
|
m_windowHandle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::InitPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // namespace MobileGL::MG_Backend
|
} // namespace MobileGL::MG_Backend
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
enum class WindowBackend {
|
enum class WindowBackend {
|
||||||
Android,
|
Android,
|
||||||
|
X11,
|
||||||
// TODO: X11, Wayland, Windows, macOS, etc.
|
// TODO: X11, Wayland, Windows, macOS, etc.
|
||||||
WindowBackendCount,
|
WindowBackendCount,
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
@@ -114,6 +115,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
|
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
|
||||||
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
|
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
|
||||||
|
virtual Bool CreateEGLPbufferSurface(EGLint width, EGLint height);
|
||||||
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||||
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
|
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
|
||||||
|
|
||||||
@@ -126,14 +128,22 @@ namespace MobileGL {
|
|||||||
virtual BackendType GetBackendType() const = 0;
|
virtual BackendType GetBackendType() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class SurfaceKind {
|
||||||
|
None,
|
||||||
|
Window,
|
||||||
|
Pbuffer
|
||||||
|
};
|
||||||
|
|
||||||
void ResetEGLRuntimeState();
|
void ResetEGLRuntimeState();
|
||||||
|
virtual Bool InitPbufferSurface(EGLint width, EGLint height);
|
||||||
|
|
||||||
mutable std::recursive_mutex m_eglStateMutex;
|
mutable std::recursive_mutex m_eglStateMutex;
|
||||||
WindowHandle m_windowHandle;
|
WindowHandle m_windowHandle;
|
||||||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
||||||
Bool m_eglDisplayInitialized = false;
|
Bool m_eglDisplayInitialized = false;
|
||||||
Bool m_eglWindowSurfaceInitialized = false;
|
Bool m_eglSurfaceInitialized = false;
|
||||||
Bool m_backendCapabilitiesInitialized = false;
|
Bool m_backendCapabilitiesInitialized = false;
|
||||||
|
SurfaceKind m_eglSurfaceKind = SurfaceKind::None;
|
||||||
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
||||||
};
|
};
|
||||||
} // namespace MG_Backend
|
} // namespace MG_Backend
|
||||||
|
|||||||
@@ -78,18 +78,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle.Backend != WindowBackend::Android || !handle.Handle) {
|
if ((handle.Backend != WindowBackend::Android && handle.Backend != WindowBackend::X11) || !handle.Handle) {
|
||||||
MGLOG_E("DirectGLES backend only supports Android native windows");
|
MGLOG_E("DirectGLES backend only supports Android and X11 native windows");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bool sameHandle =
|
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||||
if (sameHandle) {
|
if (sameHandle) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_eglWindowSurfaceInitialized) {
|
if (m_eglSurfaceInitialized) {
|
||||||
DestroyEGLContext();
|
DestroyEGLContext();
|
||||||
ResetEGLRuntimeState();
|
ResetEGLRuntimeState();
|
||||||
}
|
}
|
||||||
@@ -97,6 +97,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return BackendObject::CreateEGLWindowSurface(handle);
|
return BackendObject::CreateEGLWindowSurface(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::InitPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
return DirectGLES::InitPbufferSurface(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
Bool BackendObject_DirectGLES::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
Bool BackendObject_DirectGLES::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||||
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||||
@@ -121,7 +125,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||||
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
|
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
|
||||||
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
|
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
|
||||||
E_GL_ARB_program_interface_query},
|
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
|
||||||
|
E_GL_EXT_framebuffer_object},
|
||||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||||
},
|
},
|
||||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateDynamicBackendParameters();
|
void UpdateDynamicBackendParameters();
|
||||||
|
Bool InitPbufferSurface(EGLint width, EGLint height) override;
|
||||||
|
|
||||||
Bool m_initialized = false;
|
Bool m_initialized = false;
|
||||||
MG_External::EGLFunctionsTable m_EGLFunctions;
|
MG_External::EGLFunctionsTable m_EGLFunctions;
|
||||||
|
|||||||
@@ -1454,8 +1454,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return g_GLESFuncs.glGetProgramResourceIndex(backendProgramId, programInterface, name);
|
return g_GLESFuncs.glGetProgramResourceIndex(backendProgramId, programInterface, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
|
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length,
|
||||||
GLsizei* length, GLchar* name) {
|
GLchar* name) {
|
||||||
GLuint backendProgramId = GetBackendProgramId(program);
|
GLuint backendProgramId = GetBackendProgramId(program);
|
||||||
if (!backendProgramId) return;
|
if (!backendProgramId) return;
|
||||||
g_GLESFuncs.glGetProgramResourceName(backendProgramId, programInterface, index, bufSize, length, name);
|
g_GLESFuncs.glGetProgramResourceName(backendProgramId, programInterface, index, bufSize, length, name);
|
||||||
@@ -1465,8 +1465,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
||||||
GLuint backendProgramId = GetBackendProgramId(program);
|
GLuint backendProgramId = GetBackendProgramId(program);
|
||||||
if (!backendProgramId) return;
|
if (!backendProgramId) return;
|
||||||
g_GLESFuncs.glGetProgramResourceiv(backendProgramId, programInterface, index, propCount, props, bufSize,
|
g_GLESFuncs.glGetProgramResourceiv(backendProgramId, programInterface, index, propCount, props, bufSize, length,
|
||||||
length, params);
|
params);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name) {
|
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||||
@@ -1858,9 +1858,117 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
static EGLContext g_Context = EGL_NO_CONTEXT;
|
static EGLContext g_Context = EGL_NO_CONTEXT;
|
||||||
static EGLSurface g_Surface = EGL_NO_SURFACE;
|
static EGLSurface g_Surface = EGL_NO_SURFACE;
|
||||||
static EGLConfig g_Config = nullptr;
|
static EGLConfig g_Config = nullptr;
|
||||||
Bool InitWindowSurface(NativeWindowType window) {
|
|
||||||
// TODO: handle custom EGL paramters
|
static EGLint QueryDefaultX11VisualId() {
|
||||||
if (!window) return false;
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool GetConfigAttrib(EGLConfig config, EGLint attr, EGLint& value) {
|
||||||
|
return g_EGLFuncs.eglGetConfigAttrib && g_EGLFuncs.eglGetConfigAttrib(g_Display, config, attr, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool ConfigSupports(EGLConfig config, EGLint surfaceBit) {
|
||||||
|
EGLint surfaceType = 0;
|
||||||
|
EGLint renderableType = 0;
|
||||||
|
if (!GetConfigAttrib(config, EGL_SURFACE_TYPE, surfaceType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!GetConfigAttrib(config, EGL_RENDERABLE_TYPE, renderableType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (surfaceType & surfaceBit) && (renderableType & EGL_OPENGL_ES3_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool ChooseConfigForSurface(EGLint surfaceBit, EGLConfig& outConfig) {
|
||||||
|
const EGLint configAttribs[] = {EGL_SURFACE_TYPE, surfaceBit, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
|
||||||
|
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
|
||||||
|
EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8,
|
||||||
|
EGL_NONE};
|
||||||
|
|
||||||
|
EGLint numConfigs = 0;
|
||||||
|
if (!g_EGLFuncs.eglChooseConfig(g_Display, configAttribs, nullptr, 0, &numConfigs) || numConfigs == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<EGLConfig> configs(static_cast<SizeT>(numConfigs));
|
||||||
|
if (!g_EGLFuncs.eglChooseConfig(g_Display, configAttribs, configs.data(), numConfigs, &numConfigs) ||
|
||||||
|
numConfigs == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
configs.resize(static_cast<SizeT>(numConfigs));
|
||||||
|
|
||||||
|
if (surfaceBit == EGL_WINDOW_BIT) {
|
||||||
|
const EGLint defaultVisualId = QueryDefaultX11VisualId();
|
||||||
|
if (defaultVisualId != 0) {
|
||||||
|
for (const auto config : configs) {
|
||||||
|
EGLint nativeVisualId = 0;
|
||||||
|
if (ConfigSupports(config, surfaceBit) &&
|
||||||
|
GetConfigAttrib(config, EGL_NATIVE_VISUAL_ID, nativeVisualId) &&
|
||||||
|
nativeVisualId == defaultVisualId) {
|
||||||
|
outConfig = config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto config : configs) {
|
||||||
|
if (ConfigSupports(config, surfaceBit)) {
|
||||||
|
outConfig = config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outConfig = configs.front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool InitDisplayAndContext(EGLint surfaceBit) {
|
||||||
|
DestroyEGLContext();
|
||||||
|
|
||||||
g_Display = g_EGLFuncs.eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
g_Display = g_EGLFuncs.eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
if (g_Display == EGL_NO_DISPLAY) return false;
|
if (g_Display == EGL_NO_DISPLAY) return false;
|
||||||
@@ -1868,32 +1976,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (!g_EGLFuncs.eglInitialize(g_Display, nullptr, nullptr)) return false;
|
if (!g_EGLFuncs.eglInitialize(g_Display, nullptr, nullptr)) return false;
|
||||||
g_EGLFuncs.eglBindAPI(EGL_OPENGL_ES_API);
|
g_EGLFuncs.eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
|
||||||
const EGLint configAttribs[] = {EGL_SURFACE_TYPE,
|
if (!ChooseConfigForSurface(surfaceBit, g_Config)) return false;
|
||||||
EGL_WINDOW_BIT,
|
|
||||||
EGL_RENDERABLE_TYPE,
|
|
||||||
EGL_OPENGL_ES3_BIT,
|
|
||||||
EGL_RED_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_GREEN_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_BLUE_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_ALPHA_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_DEPTH_SIZE,
|
|
||||||
24,
|
|
||||||
EGL_STENCIL_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_NONE};
|
|
||||||
|
|
||||||
EGLint numConfigs = 0;
|
|
||||||
if (!g_EGLFuncs.eglChooseConfig(g_Display, configAttribs, &g_Config, 1, &numConfigs) || numConfigs == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||||
|
|
||||||
g_Context = g_EGLFuncs.eglCreateContext(g_Display, g_Config, EGL_NO_CONTEXT, contextAttribs);
|
g_Context = g_EGLFuncs.eglCreateContext(g_Display, g_Config, EGL_NO_CONTEXT, contextAttribs);
|
||||||
if (g_Context == EGL_NO_CONTEXT) return false;
|
return g_Context != EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool InitWindowSurface(NativeWindowType window) {
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
if (!InitDisplayAndContext(EGL_WINDOW_BIT)) return false;
|
||||||
|
|
||||||
g_Surface = g_EGLFuncs.eglCreateWindowSurface(g_Display, g_Config, window, nullptr);
|
g_Surface = g_EGLFuncs.eglCreateWindowSurface(g_Display, g_Config, window, nullptr);
|
||||||
if (g_Surface == EGL_NO_SURFACE) return false;
|
if (g_Surface == EGL_NO_SURFACE) return false;
|
||||||
@@ -1905,6 +1999,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool InitPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
if (width <= 0 || height <= 0) return false;
|
||||||
|
if (!InitDisplayAndContext(EGL_PBUFFER_BIT)) return false;
|
||||||
|
|
||||||
|
const EGLint surfaceAttribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
|
||||||
|
g_Surface = g_EGLFuncs.eglCreatePbufferSurface(g_Display, g_Config, surfaceAttribs);
|
||||||
|
if (g_Surface == EGL_NO_SURFACE) return false;
|
||||||
|
|
||||||
|
if (!g_EGLFuncs.eglMakeCurrent(g_Display, g_Surface, g_Surface, g_Context)) return false;
|
||||||
|
|
||||||
|
MGLOG_D("EGL pbuffer context created successfully: display=%p, surface=%p, context=%p. size=%dx%d", g_Display,
|
||||||
|
g_Surface, g_Context, width, height);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Present() {
|
void Present() {
|
||||||
if (g_Display != EGL_NO_DISPLAY && g_Surface != EGL_NO_SURFACE) {
|
if (g_Display != EGL_NO_DISPLAY && g_Surface != EGL_NO_SURFACE) {
|
||||||
g_EGLFuncs.eglSwapBuffers(g_Display, g_Surface);
|
g_EGLFuncs.eglSwapBuffers(g_Display, g_Surface);
|
||||||
|
|||||||
@@ -67,14 +67,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||||
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
|
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
|
||||||
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
|
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length,
|
||||||
GLsizei* length, GLchar* name);
|
GLchar* name);
|
||||||
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
|
||||||
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
|
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
||||||
Bool InitWindowSurface(NativeWindowType window);
|
Bool InitWindowSurface(NativeWindowType window);
|
||||||
|
Bool InitPbufferSurface(EGLint width, EGLint height);
|
||||||
void Present();
|
void Present();
|
||||||
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
||||||
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bool sameHandle =
|
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||||
if (sameHandle) {
|
if (sameHandle) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_eglWindowSurfaceInitialized || pVulkanRenderer) {
|
if (m_eglSurfaceInitialized || pVulkanRenderer) {
|
||||||
pVulkanRenderer.reset();
|
pVulkanRenderer.reset();
|
||||||
ResetEGLRuntimeState();
|
ResetEGLRuntimeState();
|
||||||
}
|
}
|
||||||
@@ -116,10 +116,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||||
V_OpenGL33, E_GL_ARB_draw_buffers_blend,
|
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
|
||||||
E_GL_ARB_compute_shader,
|
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
|
||||||
E_GL_ARB_shader_storage_buffer_object,
|
|
||||||
E_GL_ARB_shader_image_load_store,
|
|
||||||
E_GL_ARB_program_interface_query},
|
E_GL_ARB_program_interface_query},
|
||||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,11 +34,25 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
|||||||
MG_Backend::WindowBackend DetectWindowBackend() {
|
MG_Backend::WindowBackend DetectWindowBackend() {
|
||||||
#if defined(ANDROID) || defined(__ANDROID__)
|
#if defined(ANDROID) || defined(__ANDROID__)
|
||||||
return MG_Backend::WindowBackend::Android;
|
return MG_Backend::WindowBackend::Android;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
return MG_Backend::WindowBackend::X11;
|
||||||
#else
|
#else
|
||||||
return MG_Backend::WindowBackend::Unknown;
|
return MG_Backend::WindowBackend::Unknown;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLint GetAttribValue(const EGLint* attribList, EGLint attrib, EGLint defaultValue) {
|
||||||
|
if (!attribList) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||||
|
if (attribList[i] == attrib) {
|
||||||
|
return attribList[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename NativeType>
|
template <typename NativeType>
|
||||||
Bool IsNullNativeHandle(NativeType nativeHandle) {
|
Bool IsNullNativeHandle(NativeType nativeHandle) {
|
||||||
if constexpr (std::is_pointer_v<NativeType>) {
|
if constexpr (std::is_pointer_v<NativeType>) {
|
||||||
@@ -330,7 +344,24 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
|||||||
if (!state) {
|
if (!state) {
|
||||||
return EGL_NO_SURFACE;
|
return EGL_NO_SURFACE;
|
||||||
}
|
}
|
||||||
return state->CreatePbufferSurface(dpy, config, attrib_list);
|
const EGLint width = GetAttribValue(attrib_list, EGL_WIDTH, 1);
|
||||||
|
const EGLint height = GetAttribValue(attrib_list, EGL_HEIGHT, 1);
|
||||||
|
EGLSurface surface = state->CreatePbufferSurface(dpy, config, attrib_list);
|
||||||
|
if (surface == EGL_NO_SURFACE) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* backendObject = GetBackendObject(state);
|
||||||
|
if (!backendObject) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
if (!backendObject->CreateEGLPbufferSurface(width, height)) {
|
||||||
|
state->DestroySurface(dpy, surface);
|
||||||
|
state->SetError(EGL_BAD_ALLOC);
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
||||||
|
|||||||
@@ -17,40 +17,38 @@
|
|||||||
#include "../Framebuffer/GL_Framebuffer.h"
|
#include "../Framebuffer/GL_Framebuffer.h"
|
||||||
#include "../VertexArray/GL_VertexArray.h"
|
#include "../VertexArray/GL_VertexArray.h"
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_HEAD(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_END(type, name, ...) \
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||||
return (type)1; \
|
return (type)1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type, name, ...) \
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_HEAD(type,name,...) \
|
#define DECLARE_GL_FUNCTION_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
|
||||||
|
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
@@ -2880,6 +2878,69 @@ MOBILEGL_GL_API void glGetFramebufferParameterivEXT(GLenum target, GLenum pname,
|
|||||||
glGetFramebufferParameteriv(target, pname, params);
|
glGetFramebufferParameteriv(target, pname, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glBindFramebufferEXT(GLenum target, GLuint framebuffer) {
|
||||||
|
glBindFramebuffer(target, framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) {
|
||||||
|
glBindRenderbuffer(target, renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLenum glCheckFramebufferStatusEXT(GLenum target) {
|
||||||
|
return glCheckFramebufferStatus(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers) {
|
||||||
|
glDeleteFramebuffers(n, framebuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* renderbuffers) {
|
||||||
|
glDeleteRenderbuffers(n, renderbuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
||||||
|
GLuint renderbuffer) {
|
||||||
|
glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||||
|
GLint level) {
|
||||||
|
glFramebufferTexture2D(target, attachment, textarget, texture, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenFramebuffersEXT(GLsizei n, GLuint* framebuffers) {
|
||||||
|
glGenFramebuffers(n, framebuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenRenderbuffersEXT(GLsizei n, GLuint* renderbuffers) {
|
||||||
|
glGenRenderbuffers(n, renderbuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenerateMipmapEXT(GLenum target) {
|
||||||
|
glGenerateMipmap(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname,
|
||||||
|
GLint* params) {
|
||||||
|
glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint* params) {
|
||||||
|
glGetRenderbufferParameteriv(target, pname, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLboolean glIsFramebufferEXT(GLuint framebuffer) {
|
||||||
|
return glIsFramebuffer(framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLboolean glIsRenderbufferEXT(GLuint renderbuffer) {
|
||||||
|
return glIsRenderbuffer(renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||||
|
glRenderbufferStorage(target, internalformat, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) {
|
MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) {
|
||||||
return glGetGraphicsResetStatus();
|
return glGetGraphicsResetStatus();
|
||||||
}
|
}
|
||||||
@@ -3025,48 +3086,48 @@ MOBILEGL_GL_API void glProgramUniform4uivEXT(GLuint program, GLint location, GLs
|
|||||||
glProgramUniform4uiv(program, location, count, value);
|
glProgramUniform4uiv(program, location, count, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace MobileGL {
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr EGLint EGL_DISPLAY_MAJOR_VERSION = 1;
|
constexpr EGLint EGL_DISPLAY_MAJOR_VERSION = 1;
|
||||||
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
|
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
|
||||||
|
constexpr EGLint DEFAULT_MAX_PBUFFER_SIZE = 16384;
|
||||||
|
|
||||||
template <typename AttrType>
|
template <typename AttrType>
|
||||||
Optional<AttrType> ParseAttribValue(const AttrType* attribList, EGLint attrib) {
|
Optional<AttrType> ParseAttribValue(const AttrType* attribList, EGLint attrib) {
|
||||||
@@ -27,6 +28,55 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
return Nullopt;
|
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
|
} // namespace
|
||||||
|
|
||||||
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
|
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
|
||||||
@@ -99,30 +149,31 @@ namespace MobileGL {
|
|||||||
.SwapInterval = 1,
|
.SwapInterval = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto config = CreateDefaultConfig(display);
|
displayObject.Configs.push_back(CreateDefaultConfig(display, 1, 0));
|
||||||
displayObject.Configs.push_back(config);
|
displayObject.Configs.push_back(CreateDefaultConfig(display, 2, 8));
|
||||||
|
|
||||||
m_displays[display] = displayObject;
|
m_displays[display] = displayObject;
|
||||||
m_displayLookup[key] = display;
|
m_displayLookup[key] = display;
|
||||||
return 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++);
|
const auto config = EncodeHandle<EGLConfigHandle>(m_nextConfigHandle++);
|
||||||
ConfigObject cfg = {
|
ConfigObject cfg = {
|
||||||
.Display = display,
|
.Display = display,
|
||||||
.ConfigId = 1,
|
.ConfigId = configId,
|
||||||
.RedSize = 8,
|
.RedSize = 8,
|
||||||
.GreenSize = 8,
|
.GreenSize = 8,
|
||||||
.BlueSize = 8,
|
.BlueSize = 8,
|
||||||
.AlphaSize = 8,
|
.AlphaSize = 8,
|
||||||
.DepthSize = 24,
|
.DepthSize = 24,
|
||||||
.StencilSize = 8,
|
.StencilSize = stencilSize,
|
||||||
.SurfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_PIXMAP_BIT,
|
.SurfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_PIXMAP_BIT,
|
||||||
.RenderableType = EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT,
|
.RenderableType = EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT,
|
||||||
.MinSwapInterval = 0,
|
.MinSwapInterval = 0,
|
||||||
.MaxSwapInterval = 4,
|
.MaxSwapInterval = 4,
|
||||||
.NativeVisualId = 0,
|
.NativeVisualId = QueryDefaultX11VisualId(),
|
||||||
};
|
};
|
||||||
#if defined(ANDROID) || defined(__ANDROID__)
|
#if defined(ANDROID) || defined(__ANDROID__)
|
||||||
cfg.NativeVisualId = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
cfg.NativeVisualId = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
||||||
@@ -294,7 +345,6 @@ namespace MobileGL {
|
|||||||
Bool EGLContext::ChooseConfig(EGLDisplayHandle display, const EGLint* attribList, EGLConfigHandle* configs,
|
Bool EGLContext::ChooseConfig(EGLDisplayHandle display, const EGLint* attribList, EGLConfigHandle* configs,
|
||||||
EGLint configSize, EGLint* numConfig) {
|
EGLint configSize, EGLint* numConfig) {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
(void)attribList;
|
|
||||||
auto* displayObject = TryGetDisplay(display);
|
auto* displayObject = TryGetDisplay(display);
|
||||||
if (!displayObject) {
|
if (!displayObject) {
|
||||||
SetError(EGL_BAD_DISPLAY);
|
SetError(EGL_BAD_DISPLAY);
|
||||||
@@ -309,14 +359,84 @@ namespace MobileGL {
|
|||||||
return false;
|
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) {
|
if (!configs || configSize <= 0) {
|
||||||
return true;
|
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) {
|
for (SizeT i = 0; i < copyCount; ++i) {
|
||||||
configs[i] = displayObject->Configs[i];
|
configs[i] = matchedConfigs[i];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -356,9 +476,38 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (attribute) {
|
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:
|
case EGL_CONFIG_ID:
|
||||||
*value = cfg->ConfigId;
|
*value = cfg->ConfigId;
|
||||||
return true;
|
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:
|
case EGL_RED_SIZE:
|
||||||
*value = cfg->RedSize;
|
*value = cfg->RedSize;
|
||||||
return true;
|
return true;
|
||||||
@@ -390,9 +539,27 @@ namespace MobileGL {
|
|||||||
case EGL_MAX_SWAP_INTERVAL:
|
case EGL_MAX_SWAP_INTERVAL:
|
||||||
*value = cfg->MaxSwapInterval;
|
*value = cfg->MaxSwapInterval;
|
||||||
return true;
|
return true;
|
||||||
|
case EGL_NATIVE_RENDERABLE:
|
||||||
|
*value = EGL_TRUE;
|
||||||
|
return true;
|
||||||
case EGL_NATIVE_VISUAL_ID:
|
case EGL_NATIVE_VISUAL_ID:
|
||||||
*value = cfg->NativeVisualId;
|
*value = cfg->NativeVisualId;
|
||||||
return true;
|
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:
|
default:
|
||||||
const_cast<EGLContext*>(this)->SetError(EGL_BAD_ATTRIBUTE);
|
const_cast<EGLContext*>(this)->SetError(EGL_BAD_ATTRIBUTE);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ namespace MobileGL {
|
|||||||
static std::thread::id CurrentThreadKey();
|
static std::thread::id CurrentThreadKey();
|
||||||
|
|
||||||
EGLDisplayHandle GetOrCreateDisplay(Uint64 nativeDisplayKey, EGLenum platform);
|
EGLDisplayHandle GetOrCreateDisplay(Uint64 nativeDisplayKey, EGLenum platform);
|
||||||
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display);
|
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display, EGLint configId, EGLint stencilSize);
|
||||||
|
|
||||||
DisplayObject* TryGetDisplay(EGLDisplayHandle display);
|
DisplayObject* TryGetDisplay(EGLDisplayHandle display);
|
||||||
const DisplayObject* TryGetDisplay(EGLDisplayHandle display) const;
|
const DisplayObject* TryGetDisplay(EGLDisplayHandle display) const;
|
||||||
|
|||||||
Reference in New Issue
Block a user