diff options
Diffstat (limited to 'src/SFML/Window/DRM/DRMContext.cpp')
-rw-r--r-- | src/SFML/Window/DRM/DRMContext.cpp | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/src/SFML/Window/DRM/DRMContext.cpp b/src/SFML/Window/DRM/DRMContext.cpp new file mode 100644 index 0000000..fa6d96d --- /dev/null +++ b/src/SFML/Window/DRM/DRMContext.cpp @@ -0,0 +1,872 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2023 Andrew Mickelson +// 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/DRM/DRMContext.hpp> +#include <SFML/Window/DRM/WindowImplDRM.hpp> +#include <SFML/System/Err.hpp> +#include <SFML/System/Sleep.hpp> +#include <cerrno> +#include <cstdlib> +#include <cstring> +#include <fcntl.h> +#include <poll.h> +#include <unistd.h> +#include <xf86drm.h> + +// We check for this definition in order to avoid multiple definitions of GLAD +// entities during unity builds of SFML. +#ifndef SF_GLAD_EGL_IMPLEMENTATION_INCLUDED +#define SF_GLAD_EGL_IMPLEMENTATION_INCLUDED +#define SF_GLAD_EGL_IMPLEMENTATION +#include <glad/egl.h> +#endif + +namespace +{ + struct DrmFb + { + gbm_bo* bo; + sf::Uint32 fbId; + }; + + bool initialized = false; + sf::priv::Drm drmNode; + drmEventContext drmEventCtx; + pollfd pollFD; + gbm_device* gbmDevice = NULL; + int contextCount = 0; + EGLDisplay display = EGL_NO_DISPLAY; + int waitingForFlip = 0; + + static void pageFlipHandler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, void* data) + { + // suppress unused param warning + (void)fd, (void)frame, (void)sec, (void)usec; + + int* temp = static_cast<int*>(data); + *temp = 0; + } + + static bool waitForFlip(int timeout) + { + while (waitingForFlip) + { + pollFD.revents = 0; + + if (poll(&pollFD, 1, timeout) < 0) + return false; + + if (pollFD.revents & (POLLHUP | POLLERR)) + return false; + + if (pollFD.revents & POLLIN) + { + drmHandleEvent(drmNode.fileDescriptor, &drmEventCtx); + } + else + { + return false; + } + } + return true; + } + + void cleanup() + { + if (!initialized) + return; + + drmModeSetCrtc(drmNode.fileDescriptor, + drmNode.originalCrtc->crtc_id, + drmNode.originalCrtc->buffer_id, + drmNode.originalCrtc->x, + drmNode.originalCrtc->y, + &drmNode.connectorId, + 1, + &drmNode.originalCrtc->mode); + + drmModeFreeConnector(drmNode.savedConnector); + drmModeFreeEncoder(drmNode.savedEncoder); + drmModeFreeCrtc(drmNode.originalCrtc); + + eglTerminate(display); + display = EGL_NO_DISPLAY; + + gbm_device_destroy(gbmDevice); + gbmDevice = NULL; + + close(drmNode.fileDescriptor); + + drmNode.fileDescriptor = -1; + drmNode.mode = 0; + + std::memset(&pollFD, 0, sizeof(pollfd)); + std::memset(&drmEventCtx, 0, sizeof(drmEventContext)); + + waitingForFlip = 0; + + initialized = false; + } + + void drmFbDestroyCallback(gbm_bo* bo, void* data) + { + int drmFd = gbm_device_get_fd(gbm_bo_get_device(bo)); + DrmFb* fb = static_cast<DrmFb*>(data); + + if (fb->fbId) + drmModeRmFB(drmFd, fb->fbId); + + delete fb; + } + + DrmFb* drmFbGetFromBo(gbm_bo& bo) + { + int drmFd = gbm_device_get_fd(gbm_bo_get_device(&bo)); + DrmFb* fb = static_cast<DrmFb*>(gbm_bo_get_user_data(&bo)); + if (fb) + return fb; + + fb = new DrmFb(); + fb->bo = &bo; + + const sf::Uint32 width = gbm_bo_get_width(&bo); + const sf::Uint32 height = gbm_bo_get_height(&bo); + const sf::Uint32 format = gbm_bo_get_format(&bo); + + sf::Uint32 strides[4] = {0}; + sf::Uint32 handles[4] = {0}; + sf::Uint32 offsets[4] = {0}; + uint64_t modifiers[4] = {0}; + modifiers[0] = gbm_bo_get_modifier(&bo); + const int num_planes = gbm_bo_get_plane_count(&bo); + for (int i = 0; i < num_planes; ++i) + { + strides[i] = gbm_bo_get_stride_for_plane(&bo, i); + handles[i] = gbm_bo_get_handle(&bo).u32; + offsets[i] = gbm_bo_get_offset(&bo, i); + modifiers[i] = modifiers[0]; + } + + sf::Uint32 flags = 0; + if (modifiers[0]) + { + flags = DRM_MODE_FB_MODIFIERS; + } + + int result = drmModeAddFB2WithModifiers(drmFd, width, height, format, handles, strides, offsets, modifiers, &fb->fbId, flags); + + if (result) + { + std::memset(handles, 0, 16); + handles[0] = gbm_bo_get_handle(&bo).u32; + std::memset(strides, 0, 16); + strides[0] = gbm_bo_get_stride(&bo); + std::memset(offsets, 0, 16); + result = drmModeAddFB2(drmFd, width, height, format, handles, strides, offsets, &fb->fbId, 0); + } + + if (result) + { + sf::err() << "Failed to create fb: " << std::strerror(errno) << std::endl; + delete fb; + return NULL; + } + + gbm_bo_set_user_data(&bo, fb, drmFbDestroyCallback); + + return fb; + } + + sf::Uint32 findCrtcForEncoder(const drmModeRes& resources, const drmModeEncoder& encoder) + { + for (int i = 0; i < resources.count_crtcs; ++i) + { + // Possible_crtcs is a bitmask as described here: + // https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api + const sf::Uint32 crtcMask = 1U << i; + const sf::Uint32 crtcId = resources.crtcs[i]; + if (encoder.possible_crtcs & crtcMask) + { + return crtcId; + } + } + + // No match found + return 0; + } + + sf::Uint32 findCrtcForConnector(const sf::priv::Drm& drm, const drmModeRes& resources, const drmModeConnector& connector) + { + for (int i = 0; i < connector.count_encoders; ++i) + { + const sf::Uint32 encoderId = connector.encoders[i]; + const drmModeEncoderPtr encoder = drmModeGetEncoder(drm.fileDescriptor, encoderId); + + if (encoder) + { + const sf::Uint32 crtcId = findCrtcForEncoder(resources, *encoder); + + drmModeFreeEncoder(encoder); + if (crtcId != 0) + { + return crtcId; + } + } + } + + // No match found + return 0; + } + + int getResources(int fd, drmModeResPtr& resources) + { + resources = drmModeGetResources(fd); + if (resources == NULL) + return -1; + return 0; + } + + int hasMonitorConnected(int fd, drmModeRes& resources) + { + drmModeConnectorPtr connector; + for (int i = 0; i < resources.count_connectors; ++i) + { + connector = drmModeGetConnector(fd, resources.connectors[i]); + if (connector->connection == DRM_MODE_CONNECTED) + { + // There is a monitor connected + drmModeFreeConnector(connector); + connector = NULL; + return 1; + } + drmModeFreeConnector(connector); + connector = NULL; + } + return 0; + } + + int findDrmDevice(drmModeResPtr& resources) + { + static const int maxDrmDevices = 64; + + drmDevicePtr devices[maxDrmDevices] = { NULL }; + + const int numDevices = drmGetDevices2(0, devices, maxDrmDevices); + if (numDevices < 0) + { + sf::err() << "drmGetDevices2 failed: " << std::strerror(-numDevices) << std::endl; + return -1; + } + + int fileDescriptor = -1; + for (int i = 0; i < numDevices; ++i) + { + drmDevicePtr device = devices[i]; + int result = 0; + + if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY))) + continue; + // OK, it's a primary device. If we can get the drmModeResources, it means it's also a KMS-capable device. + fileDescriptor = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR); + if (fileDescriptor < 0) + continue; + result = getResources(fileDescriptor, resources); +#ifdef SFML_DEBUG + sf::err() << "DRM device used: " << i << std::endl; +#endif + if(!result && hasMonitorConnected(fileDescriptor, *resources) != 0) + break; + close(fileDescriptor); + fileDescriptor = -1; + } + drmFreeDevices(devices, numDevices); + + if (fileDescriptor < 0) + sf::err() << "No drm device found!" << std::endl; + return fileDescriptor; + } + + int initDrm(sf::priv::Drm& drm, const char* device, const char* modeStr, unsigned int vrefresh) + { + drmModeResPtr resources; + + if (device) + { + drm.fileDescriptor = open(device, O_RDWR); + const int ret = getResources(drm.fileDescriptor, resources); + if (ret < 0 && errno == EOPNOTSUPP) + sf::err() << device << " does not look like a modeset device" << std::endl; + } + else + { + drm.fileDescriptor = findDrmDevice(resources); + } + + if (drm.fileDescriptor < 0) + { + sf::err() << "Could not open drm device" << std::endl; + return -1; + } + + if (!resources) + { + sf::err() << "drmModeGetResources failed: " << std::strerror(errno) << std::endl; + return -1; + } + + // Find a connected connector: + drmModeConnectorPtr connector = NULL; + for (int i = 0; i < resources->count_connectors; ++i) + { + connector = drmModeGetConnector(drm.fileDescriptor, resources->connectors[i]); + if (connector->connection == DRM_MODE_CONNECTED) + { + // It's connected, let's use this! + break; + } + drmModeFreeConnector(connector); + connector = NULL; + } + + if (!connector) + { + // We could be fancy and listen for hotplug events and wait for a connector.. + sf::err() << "No connected connector!" << std::endl; + return -1; + } + + // Find user requested mode: + if (modeStr && *modeStr) + { + for (int i = 0; i < connector->count_modes; ++i) + { + drmModeModeInfoPtr currentMode = &connector->modes[i]; + + if (std::strcmp(currentMode->name, modeStr) == 0) + { + if (vrefresh == 0 || currentMode->vrefresh == vrefresh) + { + drm.mode = currentMode; + break; + } + } + } + if (!drm.mode) + sf::err() << "Requested mode not found, using default mode!" << std::endl; + } + + // Find encoder: + drmModeEncoderPtr encoder = NULL; + for (int i = 0; i < resources->count_encoders; ++i) + { + encoder = drmModeGetEncoder(drm.fileDescriptor, resources->encoders[i]); + if (encoder->encoder_id == connector->encoder_id) + break; + drmModeFreeEncoder(encoder); + encoder = NULL; + } + + if (encoder) + { + drm.crtcId = encoder->crtc_id; + } + else + { + const sf::Uint32 crtcId = findCrtcForConnector(drm, *resources, *connector); + if (crtcId == 0) + { + sf::err() << "No crtc found!" << std::endl; + return -1; + } + + drm.crtcId = crtcId; + } + + drmModeFreeResources(resources); + + drm.connectorId = connector->connector_id; + + drm.savedConnector = connector; + drm.savedEncoder = encoder; + + // Get original display mode so we can restore display mode after program exits + drm.originalCrtc = drmModeGetCrtc(drm.fileDescriptor, drm.crtcId); + + // Let's use the current mode rather than the preferred one if the user didn't specify a mode with env vars + if (!drm.mode) + { +#ifdef SFML_DEBUG + sf::err() << "DRM using the current mode" << std::endl; +#endif + drm.mode = &(drm.originalCrtc->mode); + } + +#ifdef SFML_DEBUG + sf::err() << "DRM Mode used: " << drm.mode->name << "@" << drm.mode->vrefresh << std::endl; +#endif + + return 0; + } + + void checkInit() + { + if (initialized) + return; + + // Use environment variable "SFML_DRM_DEVICE" (or NULL if not set) + char* deviceString = std::getenv("SFML_DRM_DEVICE"); + if (deviceString && !*deviceString) + deviceString = NULL; + + // Use environment variable "SFML_DRM_MODE" (or NULL if not set) + char* modeString = std::getenv("SFML_DRM_MODE"); + + // Use environment variable "SFML_DRM_REFRESH" (or 0 if not set) + // Use in combination with mode to request specific refresh rate for the mode + // if multiple refresh rates for same mode might be supported + unsigned int refreshRate = 0; + char* refreshString = std::getenv("SFML_DRM_REFRESH"); + + if (refreshString) + refreshRate = static_cast<unsigned int>(atoi(refreshString)); + + if (initDrm(drmNode, + deviceString, // device + modeString, // requested mode + refreshRate) < 0) // screen refresh rate + { + sf::err() << "Error initializing DRM" << std::endl; + return; + } + + gbmDevice = gbm_create_device(drmNode.fileDescriptor); + + std::atexit(cleanup); + initialized = true; + + pollFD.fd = drmNode.fileDescriptor; + pollFD.events = POLLIN; + drmEventCtx.version = 2; + drmEventCtx.page_flip_handler = pageFlipHandler; + } + + EGLDisplay getInitializedDisplay() + { + checkInit(); + + if (display == EGL_NO_DISPLAY) + { + gladLoaderLoadEGL(EGL_NO_DISPLAY); + + eglCheck(display = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(gbmDevice))); + + EGLint major, minor; + eglCheck(eglInitialize(display, &major, &minor)); + + gladLoaderLoadEGL(display); + +#if defined(SFML_OPENGL_ES) + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + sf::err() << "failed to bind api EGL_OPENGL_ES_API" << std::endl; + } +#else + if (!eglBindAPI(EGL_OPENGL_API)) + { + sf::err() << "failed to bind api EGL_OPENGL_API" << std::endl; + } +#endif + } + + return display; + } +} + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +DRMContext::DRMContext(DRMContext* shared) : +m_display (EGL_NO_DISPLAY), +m_context (EGL_NO_CONTEXT), +m_surface (EGL_NO_SURFACE), +m_config (NULL), +m_currentBO (NULL), +m_nextBO (NULL), +m_gbmSurface (NULL), +m_width (0), +m_height (0), +m_shown (false), +m_scanOut (false) +{ + contextCount++; + + // Get the initialized EGL display + m_display = getInitializedDisplay(); + + // Get the best EGL config matching the default video settings + m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + updateSettings(); + + // Create EGL context + createContext(shared); + + if (shared) + createSurface(shared->m_width, shared->m_height, VideoMode::getDesktopMode().bitsPerPixel, false); + else // create a surface to force the GL to initialize (seems to be required for glGetString() etc ) + createSurface(1, 1, VideoMode::getDesktopMode().bitsPerPixel, false); +} + + +//////////////////////////////////////////////////////////// +DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : +m_display (EGL_NO_DISPLAY), +m_context (EGL_NO_CONTEXT), +m_surface (EGL_NO_SURFACE), +m_config (NULL), +m_currentBO (NULL), +m_nextBO (NULL), +m_gbmSurface (NULL), +m_width (0), +m_height (0), +m_shown (false), +m_scanOut (false) +{ + contextCount++; + + // Get the initialized EGL display + m_display = getInitializedDisplay(); + + // Get the best EGL config matching the requested video settings + m_config = getBestConfig(m_display, bitsPerPixel, settings); + updateSettings(); + + // Create EGL context + createContext(shared); + + if (owner) + { + Vector2u size = owner->getSize(); + createSurface(size.x, size.y, bitsPerPixel, true); + } +} + + +//////////////////////////////////////////////////////////// +DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) : +m_display (EGL_NO_DISPLAY), +m_context (EGL_NO_CONTEXT), +m_surface (EGL_NO_SURFACE), +m_config (NULL), +m_currentBO (NULL), +m_nextBO (NULL), +m_gbmSurface (NULL), +m_width (0), +m_height (0), +m_shown (false), +m_scanOut (false) +{ + contextCount++; + + // Get the initialized EGL display + m_display = getInitializedDisplay(); + + // Get the best EGL config matching the requested video settings + m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, settings); + updateSettings(); + + // Create EGL context + createContext(shared); + createSurface(width, height, VideoMode::getDesktopMode().bitsPerPixel, false); +} + + +//////////////////////////////////////////////////////////// +DRMContext::~DRMContext() +{ + // Deactivate the current context + EGLContext currentContext; + eglCheck(currentContext = eglGetCurrentContext()); + + if (currentContext == m_context) + { + eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); + } + + // Destroy context + if (m_context != EGL_NO_CONTEXT) + { + eglCheck(eglDestroyContext(m_display, m_context)); + m_context = EGL_NO_CONTEXT; + } + + // Destroy surface + if (m_surface != EGL_NO_SURFACE) + { + eglCheck(eglDestroySurface(m_display, m_surface)); + m_surface = EGL_NO_SURFACE; + } + + if (m_currentBO) + gbm_surface_release_buffer(m_gbmSurface, m_currentBO); + + if (m_nextBO) + gbm_surface_release_buffer(m_gbmSurface, m_nextBO); + + if (m_gbmSurface) + gbm_surface_destroy(m_gbmSurface); + + contextCount--; + if (contextCount == 0) + cleanup(); +} + + +//////////////////////////////////////////////////////////// +bool DRMContext::makeCurrent(bool current) +{ + const EGLSurface surface = current ? m_surface : EGL_NO_SURFACE; + const EGLContext context = current ? m_context : EGL_NO_CONTEXT; + return m_surface != EGL_NO_SURFACE && eglMakeCurrent(m_display, surface, surface, context); +} + + +//////////////////////////////////////////////////////////// +void DRMContext::display() +{ + if (m_surface == EGL_NO_SURFACE) + return; + + if (!m_scanOut) + { + eglCheck(eglSwapBuffers(m_display, m_surface)); + return; + } + + // Handle display of buffer to the screen + DrmFb* fb = NULL; + + if (!waitForFlip(-1)) + return; + + if (m_currentBO) + { + gbm_surface_release_buffer(m_gbmSurface, m_currentBO); + m_currentBO = NULL; + } + + eglCheck(eglSwapBuffers(m_display, m_surface)); + + m_currentBO = m_nextBO; + + // This call must be preceeded by a single call to eglSwapBuffers() + m_nextBO = gbm_surface_lock_front_buffer(m_gbmSurface); + + if (!m_nextBO) + return; + + fb = drmFbGetFromBo(*m_nextBO); + if (!fb) + { + err() << "Failed to get FB from buffer object" << std::endl; + return; + } + + // If first time, need to first call drmModeSetCrtc() + if (!m_shown) + { + if (drmModeSetCrtc(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, 0, 0, &drmNode.connectorId, 1, drmNode.mode)) + { + err() << "Failed to set mode: " << std::strerror(errno) << std::endl; + std::abort(); + } + m_shown = true; + } + + // Do page flip + if (!drmModePageFlip(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip)) + waitingForFlip = 1; +} + + +//////////////////////////////////////////////////////////// +void DRMContext::setVerticalSyncEnabled(bool enabled) +{ + eglCheck(eglSwapInterval(m_display, enabled ? 1 : 0)); +} + + +//////////////////////////////////////////////////////////// +void DRMContext::createContext(DRMContext* shared) +{ + const EGLint contextVersion[] = + { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_NONE + }; + + EGLContext toShared; + + if (shared) + toShared = shared->m_context; + else + toShared = EGL_NO_CONTEXT; + + if (toShared != EGL_NO_CONTEXT) + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + // Create EGL context + eglCheck(m_context = eglCreateContext(m_display, m_config, toShared, contextVersion)); + if (m_context == EGL_NO_CONTEXT) + err() << "Failed to create EGL context" << std::endl; +} + + +//////////////////////////////////////////////////////////// +void DRMContext::createSurface(unsigned int width, unsigned int height, unsigned int /*bpp*/, bool scanout) +{ + sf::Uint32 flags = GBM_BO_USE_RENDERING; + + m_scanOut = scanout; + if (m_scanOut) + flags |= GBM_BO_USE_SCANOUT; + + m_gbmSurface = gbm_surface_create( + gbmDevice, + width, + height, + GBM_FORMAT_ARGB8888, + flags); + + if (!m_gbmSurface) + { + err() << "Failed to create gbm surface." << std::endl; + return; + } + + m_width = width; + m_height = height; + + eglCheck(m_surface = eglCreateWindowSurface(m_display, m_config, reinterpret_cast<EGLNativeWindowType>(m_gbmSurface), NULL)); + + if (m_surface == EGL_NO_SURFACE) + { + err() << "Failed to create EGL Surface" << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +void DRMContext::destroySurface() +{ + eglCheck(eglDestroySurface(m_display, m_surface)); + m_surface = EGL_NO_SURFACE; + + gbm_surface_destroy(m_gbmSurface); + m_gbmSurface = NULL; + + // Ensure that this context is no longer active since our surface is now destroyed + setActive(false); +} + + +//////////////////////////////////////////////////////////// +EGLConfig DRMContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings) +{ + // Set our video settings constraint + const EGLint attributes[] = + { + EGL_BUFFER_SIZE, static_cast<EGLint>(bitsPerPixel), + EGL_DEPTH_SIZE, static_cast<EGLint>(settings.depthBits), + EGL_STENCIL_SIZE, static_cast<EGLint>(settings.stencilBits), + EGL_SAMPLE_BUFFERS, static_cast<EGLint>(settings.antialiasingLevel), + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_ALPHA_SIZE, 8, + + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, +#if defined(SFML_OPENGL_ES) + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, +#else + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, +#endif + EGL_NONE + }; + + EGLint configCount; + EGLConfig configs[1]; + + // Ask EGL for the best config matching our video settings + eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount)); + + return configs[0]; +} + + +//////////////////////////////////////////////////////////// +void DRMContext::updateSettings() +{ + EGLint tmp; + + // Update the internal context settings with the current config + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp)); + m_settings.depthBits = static_cast<unsigned int>(tmp); + + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp)); + m_settings.stencilBits = static_cast<unsigned int>(tmp); + + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp)); + m_settings.antialiasingLevel = static_cast<unsigned int>(tmp); + + m_settings.majorVersion = 1; + m_settings.minorVersion = 1; + m_settings.attributeFlags = ContextSettings::Default; +} + + +//////////////////////////////////////////////////////////// +GlFunctionPointer DRMContext::getFunction(const char* name) +{ + return reinterpret_cast<GlFunctionPointer>(eglGetProcAddress(name)); +} + + +//////////////////////////////////////////////////////////// +Drm& DRMContext::getDRM() +{ + checkInit(); + return drmNode; +} + +} // namespace priv + +} // namespace sf |