3#include "GLFuncPointers.h"
6#include "../IGraphicsDevice.h"
7#include "Foundation/Logging/Logger.h"
8#include "Foundation/StringView.h"
9#include "Foundation/Platform/WindowData.h"
14PFNEGLGETPROCADDRESSPROC _eglGetProcAddress =
nullptr;
21static bool initialized =
false;
25#define _eglBindAPI eglBindAPI
26#define _eglChooseConfig eglChooseConfig
27#define _eglCreateContext eglCreateContext
28#define _eglCreateWindowSurface eglCreateWindowSurface
29#define _eglDestroyContext eglDestroyContext
30#define _eglDestroySurface eglDestroySurface
31#define _eglGetConfigAttrib eglGetConfigAttrib
32#define _eglGetDisplay eglGetDisplay
33#define _eglGetError eglGetError
34#define _eglGetPlatformDisplay eglGetPlatformDisplay
35#define _eglGetProcAddress eglGetProcAddress
36#define _eglInitialize eglInitialize
37#define _eglMakeCurrent eglMakeCurrent
38#define _eglQueryString eglQueryString
39#define _eglSwapBuffers eglSwapBuffers
40#define _eglTerminate eglTerminate
42 bool initialize() {
return true; }
46 PFNEGLBINDAPIPROC _eglBindAPI =
nullptr;
47 PFNEGLCHOOSECONFIGPROC _eglChooseConfig =
nullptr;
48 PFNEGLCREATECONTEXTPROC _eglCreateContext =
nullptr;
49 PFNEGLCREATEWINDOWSURFACEPROC _eglCreateWindowSurface =
nullptr;
50 PFNEGLDESTROYCONTEXTPROC _eglDestroyContext =
nullptr;
51 PFNEGLDESTROYSURFACEPROC _eglDestroySurface =
nullptr;
52 PFNEGLGETCONFIGATTRIBPROC _eglGetConfigAttrib =
nullptr;
53 PFNEGLGETDISPLAYPROC _eglGetDisplay =
nullptr;
54 PFNEGLGETPLATFORMDISPLAYPROC _eglGetPlatformDisplay =
nullptr;
55 PFNEGLGETERRORPROC _eglGetError =
nullptr;
56 PFNEGLINITIALIZEPROC _eglInitialize =
nullptr;
57 PFNEGLMAKECURRENTPROC _eglMakeCurrent =
nullptr;
58 PFNEGLQUERYSTRINGPROC _eglQueryString =
nullptr;
59 PFNEGLSWAPBUFFERSPROC _eglSwapBuffers =
nullptr;
60 PFNEGLTERMINATEPROC _eglTerminate =
nullptr;
62 PFNEGLGETDISPLAYDRIVERCONFIGPROC _eglGetDisplayDriverConfig =
nullptr;
63 PFNEGLGETDISPLAYDRIVERNAMEPROC _eglGetDisplayDriverName =
nullptr;
65 void* libEGL =
nullptr;
66 static const char* libEGLNames[] = {
73 { (
void**)&_eglBindAPI,
"eglBindAPI" },
74 { (
void**)&_eglChooseConfig,
"eglChooseConfig" },
75 { (
void**)&_eglCreateContext,
"eglCreateContext" },
76 { (
void**)&_eglCreateWindowSurface,
"eglCreateWindowSurface" },
77 { (
void**)&_eglDestroyContext,
"eglDestroyContext" },
78 { (
void**)&_eglDestroySurface,
"eglDestroySurface" },
79 { (
void**)&_eglGetConfigAttrib,
"eglGetConfigAttrib" },
80 { (
void**)&_eglGetDisplay,
"eglGetDisplay" },
81 { (
void**)&_eglGetError,
"eglGetError" },
82 { (
void**)&_eglGetPlatformDisplay,
"eglGetPlatformDisplay" },
83 { (
void**)&_eglInitialize,
"eglInitialize" },
84 { (
void**)&_eglMakeCurrent,
"eglMakeCurrent" },
85 { (
void**)&_eglQueryString,
"eglQueryString" },
86 { (
void**)&_eglSwapBuffers,
"eglSwapBuffers" },
87 { (
void**)&_eglTerminate,
"eglTerminate" },
93 for (
const char* libEGLName : libEGLNames) {
94 libEGL = dlopen(libEGLName, RTLD_LAZY | RTLD_LOCAL);
95 if (libEGL) {
goto egl_loaded; }
97 LOG_FATAL(logger,
"Failed to load libEGL");
102 _eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)dlsym(libEGL,
"eglGetProcAddress");
103 if(_eglGetProcAddress ==
nullptr) {
104 LOG_FATAL(logger,
"Failed to lookup libEGL function eglGetProcAddress");
108 for (
const auto& libFunc : libEGLFuncs) {
109 *libFunc.ptr = (
void*)_eglGetProcAddress(libFunc.name);
110 if(*libFunc.ptr ==
nullptr) {
111 LOG_FATAL(logger,
"Failed to look up libEGL function %s", libFunc.name);
121 const char* eglErrorString(EGLint error)
124 case EGL_SUCCESS:
return "EGL_SUCCESS";
125 case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
126 case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
127 case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
128 case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
129 case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
130 case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
131 case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
132 case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
133 case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
134 case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
135 case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
136 case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
137 case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
138 case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
146 EGLConfig chooseConfig(EGLDisplay eglDisplay, EGLint surfaceType, EGLint requestedSampleCount)
148 EGLint attribList[] =
151 EGL_SURFACE_TYPE, surfaceType,
156 EGLint numConfigs = 0;
157 if (!_eglChooseConfig(eglDisplay, attribList,
nullptr, 0, &numConfigs)) {
158 LOG_ERROR(logger,
"Failed to choose EGL config: %s", eglErrorString(_eglGetError()));
161 if(numConfigs == 0) {
162 LOG_FATAL(logger,
"eglChooseConfig return 0 matching configs");
165 std::vector<EGLConfig> configs(numConfigs);
166 if (!_eglChooseConfig(eglDisplay, attribList, configs.data(), numConfigs, &numConfigs)) {
167 LOG_FATAL(logger,
"Failed to choose EGL config: %s", eglErrorString(_eglGetError()));
172 EGLint bestSampleCount = -1;
173 LOG_DEBUG(logger,
"eglChooseConfig returned %d configs:", numConfigs);
174 for(EGLint i=0; i<numConfigs; i++) {
179 { EGL_NATIVE_VISUAL_ID },
185 { EGL_SURFACE_TYPE },
186 { EGL_SAMPLE_BUFFERS },
189 for(
auto& attrib : a) {
190 if(!_eglGetConfigAttrib(eglDisplay, configs[i], attrib.a, &attrib.v)) {
191 LOG_ERROR(logger,
"eglGetConfigAttrib failed for attribute 0x%x: %s", attrib.a, eglErrorString(_eglGetError()));
195 EGLint sampleBuffers = a[7].v;
196 EGLint sampleCount = a[8].v;
197 if ((bestFbc < 0) || (sampleBuffers && (bestSampleCount < sampleCount) && (sampleCount <= requestedSampleCount))) {
199 bestSampleCount = sampleCount;
201 LOG_DEBUG(logger,
"%i: conf=0x%zx vid=0x%x, rgba={%d %d %d %d} d=%d surfype=0x%x sampleBufs=%d samples=%d",
202 i, (
size_t)configs[i], a[0].v,
203 a[1].v, a[2].v, a[2].v, a[4].v, a[5].v,
204 a[6].v, sampleBuffers, sampleCount);
206 LOG_DEBUG(logger,
"Requested %d samples, chose config %d", requestedSampleCount, bestFbc);
212 static bool has_EGL_KHR_no_config_context =
false;
213 static bool has_EGL_MESA_query_driver =
false;
215 void queryDisplayExtensions(EGLDisplay eglDisplay)
217 if(
const char* eglExtensions = _eglQueryString(eglDisplay, EGL_EXTENSIONS); eglExtensions) {
218 for(
const char* a=eglExtensions; a && *a!=
'\0'; ) {
220 while(*b !=
' ' && *b !=
'\0') b++;
222 LOG_DEBUG(logger,
"EGL extension %.*s", StringViewFormat(extension));
225 has_EGL_KHR_no_config_context = true;
227#ifndef __EMSCRIPTEN__
229 _eglGetDisplayDriverName = (PFNEGLGETDISPLAYDRIVERNAMEPROC)_eglGetProcAddress(
"eglGetDisplayDriverName");
230 _eglGetDisplayDriverConfig = (PFNEGLGETDISPLAYDRIVERCONFIGPROC)_eglGetProcAddress(
"eglGetDisplayDriverConfig");
231 has_EGL_MESA_query_driver =
true;
235 while(*b ==
' ' && *b !=
'\0') b++;
240 LOG_DEBUG(logger,
"No EGL extensions");
242 if(has_EGL_MESA_query_driver) {
243#ifndef __EMSCRIPTEN__
244 LOG_DEBUG(logger,
"EGL display driver: %s", _eglGetDisplayDriverName(eglDisplay));
254bool Cogs::GLContext::create(NativeDisplay display, WindowData* windowData, GLContext* shareContext,
const GraphicsDeviceSettings* settings, Platform desiredPlatform,
bool debug)
256 assert(eglDisplay ==
nullptr);
257 assert(eglContext ==
nullptr);
258 assert(eglSurface ==
nullptr);
260 if (!initialize())
return false;
264 if(shareContext && shareContext->eglDisplay != EGL_NO_DISPLAY) {
265 eglDisplay = shareContext->eglDisplay;
273 eglDisplay = _eglGetPlatformDisplay(EGL_PLATFORM_X11_EXT, display, NULL);
275 eglDisplay = _eglGetDisplay(display);
280 PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
reinterpret_cast<PFNEGLQUERYDEVICESEXTPROC
>(_eglGetProcAddress(
"eglQueryDevicesEXT"));
281 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC
>(_eglGetProcAddress(
"eglGetPlatformDisplayEXT"));
283 if(eglQueryDevicesEXT && eglGetPlatformDisplayEXT){
284 constexpr int maxDevices = 4;
285 EGLDeviceEXT eglDevs[maxDevices];
288 _eglQueryDevicesEXT(maxDevices, eglDevs, &numDevices);
289 eglDisplay = _eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevs[0], 0);
292 eglDisplay = _eglGetDisplay(EGL_DEFAULT_DISPLAY);
295 eglDisplay = _eglGetDisplay(EGL_DEFAULT_DISPLAY);
298 if (eglDisplay == EGL_NO_DISPLAY) {
299 LOG_FATAL(logger,
"Failed to aquire EGL display: %s", eglErrorString(_eglGetError()));
307 if (!_eglInitialize(eglDisplay, &major, &minor)) {
308 LOG_FATAL(logger,
"Failed to initialize EGL: %s", eglErrorString(_eglGetError()));
311 LOG_DEBUG(logger,
"EGL %d.%d initialized", major, minor);
312 LOG_DEBUG(logger,
"EGL vendor: %s", _eglQueryString(eglDisplay, EGL_VENDOR));
313 LOG_DEBUG(logger,
"EGL version: %s", _eglQueryString(eglDisplay, EGL_VERSION));
314 LOG_DEBUG(logger,
"EGL client APIs: %s", _eglQueryString(eglDisplay, EGL_CLIENT_APIS));
316 if(desiredPlatform == Platform::ES3) {
317 if((major == 1) && (minor < 2)) {
318 LOG_FATAL(logger,
"Insufficient EGL version, minimum supported is 1.2");
321 if (!_eglBindAPI(EGL_OPENGL_ES_API)) {
322 LOG_FATAL(logger,
"Failed to bind OPENGL ES API");
327 if((major == 1) && (minor < 4)) {
328 LOG_FATAL(logger,
"Insufficient EGL version for OpenGL usage, minimum supported is 1.4");
331 if (!_eglBindAPI(EGL_OPENGL_API)) {
332 LOG_FATAL(logger,
"Failed to bind OPENGL API");
340 queryDisplayExtensions(eglDisplay);
343 EGLConfig config =
nullptr;
346 if(windowData && windowData->windowHandle) {
349 config = chooseConfig(eglDisplay, EGL_WINDOW_BIT, settings ? settings->numSamples : 0);
350 if(!config)
return false;
353 eglSurface = _eglCreateWindowSurface(eglDisplay, config, windowData->windowHandle,
nullptr);
354 if (eglSurface == EGL_NO_SURFACE) {
355 LOG_FATAL(logger,
"Failed to create EGL window surface: %s", eglErrorString(_eglGetError()));
363 static constexpr EGLint attributes[] = {
370 eglSurface = _eglCreatePbufferSurface(eglDisplay, config, attributes);
371 if (eglSurface == EGL_NO_SURFACE) {
372 LOG_FATAL(logger,
"Failed to create EGL pbuffer surface: %s", eglErrorString(_eglGetError()));
379 if(has_EGL_KHR_no_config_context && shareContext && shareContext->eglContext) {
380 eglContext = shareContext->eglContext;
383 std::vector<EGLint> contextAttributes;
384 switch (desiredPlatform) {
386 contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION);
387 contextAttributes.push_back(3);
391 contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION);
392 contextAttributes.push_back(4);
393 contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION);
394 contextAttributes.push_back(3);
404 #ifndef __EMSCRIPTEN__
406 contextAttributes.push_back(EGL_CONTEXT_FLAGS_KHR);
407 contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
410 contextAttributes.push_back(EGL_NONE);
411 contextAttributes.push_back(EGL_NONE);
413 if(!config && !has_EGL_KHR_no_config_context) {
414 config = chooseConfig(eglDisplay, 0, settings ? settings->numSamples : 0);
415 if(!config)
return false;
418 eglContext = _eglCreateContext(eglDisplay,
419 has_EGL_KHR_no_config_context ?
nullptr : config,
420 shareContext ? shareContext->eglContext : EGL_CAST(::EGLContext, 0),
421 contextAttributes.data());
423 LOG_ERROR(logger,
"Failed to create EGL context: %s", eglErrorString(_eglGetError()));
426 LOG_DEBUG(logger,
"Created EGL context");
431#ifndef __EMSCRIPTEN__
436 Cogs::setUpGLDebugging(
nullptr, platform);
442 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
448bool Cogs::GLContext::makeCurrent()
450 if (!_eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
451 LOG_ERROR_ONCE(logger,
"Failed to make EGL context current: %s", eglErrorString(_eglGetError()));
458void Cogs::GLContext::swapBuffers(uint32_t , uint32_t )
460#ifndef __EMSCRIPTEN__
462 if(!_eglSwapBuffers(eglDisplay, eglSurface)) {
463 LOG_ERROR_ONCE(logger,
"Failed to swap EGL buffers: %s", eglErrorString(_eglGetError()));
470void Cogs::GLContext::destroy()
474 _eglDestroySurface(eglDisplay, eglSurface);
475 eglSurface =
nullptr;
479 _eglDestroyContext(eglDisplay, eglContext);
481 eglContext =
nullptr;
484 _eglTerminate(eglDisplay);
486 eglDisplay =
nullptr;
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.