* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
* and Linux systems.
*
* Copyright (C) 2018 NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>.
*/
#include "NvCtrlAttributes.h"
#include "NvCtrlAttributesPrivate.h"
#include "NVCtrlLib.h"
#include "common-utils.h"
#include "msg.h"
#include "parse.h"
#include "wayland-connector.h"
#include <X11/extensions/xf86vmode.h>
#include <X11/extensions/Xvlib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <sys/utsname.h>
#include <dlfcn.h>
#include <EGL/egl.h>
typedef struct __libEGLInfoRec {
void *handle;
int ref_count;
EGLBoolean (* eglInitialize) (EGLDisplay,
EGLint *, EGLint *);
EGLBoolean (* eglTerminate) (EGLDisplay);
EGLDisplay (* eglGetDisplay) (NativeDisplayType);
const char * (* eglQueryString) (EGLDisplay, EGLint);
EGLBoolean (* eglGetConfigs) (EGLDisplay, EGLConfig,
EGLint, EGLint *);
EGLBoolean (* eglGetConfigAttrib) (EGLDisplay, EGLConfig,
EGLint, EGLint *);
} __libEGLInfo;
static __libEGLInfo *__libEGL = NULL;
*
* Provides a way to communicate EGL settings.
*
*
* Currently available attributes:
*
* EGL --------------------------
*
* egl_vendor_str - STR
* egl_version_str - STR
* egl_extensions - STR
*
*
* EGL Frame Buffer Information ----
*
* fbconfigs_attrib - ARRAY of EGLConfigAttr
*
****/
*
* Opens libEGL for usage
*
****/
static Bool open_libegl(void)
{
const char *error_str = NULL;
if ( !__libEGL ) {
__libEGL = nvalloc(sizeof(__libEGLInfo));
}
if ( __libEGL->handle ) {
__libEGL->ref_count++;
return True;
}
__libEGL->handle = dlopen("libEGL.so.1", RTLD_LAZY);
if ( !__libEGL->handle ) {
error_str = dlerror();
goto fail;
}
__libEGL->eglInitialize =
NV_DLSYM(__libEGL->handle, "eglInitialize");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->eglTerminate =
NV_DLSYM(__libEGL->handle, "eglTerminate");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->eglGetDisplay =
NV_DLSYM(__libEGL->handle, "eglGetDisplay");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->eglQueryString =
NV_DLSYM(__libEGL->handle, "eglQueryString");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->eglGetConfigs =
NV_DLSYM(__libEGL->handle, "eglGetConfigs");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->eglGetConfigAttrib =
NV_DLSYM(__libEGL->handle, "eglGetConfigAttrib");
if ((error_str = dlerror()) != NULL) goto fail;
__libEGL->ref_count++;
return True;
fail:
if ( error_str ) {
nv_error_msg("libEGL setup error : %s\n", error_str);
}
if ( __libEGL ) {
if ( __libEGL->handle ) {
dlclose(__libEGL->handle);
__libEGL->handle = NULL;
}
free(__libEGL);
__libEGL = NULL;
}
return False;
}
*
* Closes libEGL -
*
****/
static void close_libegl(void)
{
if ( __libEGL && __libEGL->handle && __libEGL->ref_count ) {
__libEGL->ref_count--;
if ( __libEGL->ref_count == 0 ) {
dlclose(__libEGL->handle);
__libEGL->handle = NULL;
free(__libEGL);
__libEGL = NULL;
}
}
}
*
* NvCtrlEglDelayedInit()
*
* Resolves get_wayland_display and gets the EGL Display needed.
*
****/
Bool NvCtrlEglDelayedInit(NvCtrlAttributePrivateHandle *h)
{
int major, minor;
if (!h || !h->egl || !__libEGL) {
return False;
} else if (h->egl_dpy) {
return True;
}
h->wayland_dpy = wconn_get_wayland_display();
if (h->nv) {
h->egl_dpy = __libEGL->eglGetDisplay(h->dpy);
} else {
h->egl_dpy = __libEGL->eglGetDisplay(h->wayland_dpy);
}
if (!__libEGL->eglInitialize(h->egl_dpy, &major, &minor)) {
h->egl_dpy = NULL;
return False;
}
return (h->egl_dpy != EGL_NO_DISPLAY);
}
*
* NvCtrlInitEglAttributes()
*
* Initializes the NvCtrlEglAttributes Extension by linking the libEGL.so.1 and
* resolving functions used to retrieve EGL information.
*
****/
Bool NvCtrlInitEglAttributes (NvCtrlAttributePrivateHandle *h)
{
if (!h || (!h->dpy && h->target_type == X_SCREEN_TARGET) ||
(!wconn_wayland_handle_loaded() && h->target_type == GPU_TARGET)) {
return NvCtrlBadHandle;
}
if ( !open_libegl() ) {
return False;
}
return True;
}
*
* NvCtrlEglAttributesClose()
*
* Frees and relinquishes any resource used by the NvCtrlEglAttributes
* extension.
*
****/
void
NvCtrlEglAttributesClose (NvCtrlAttributePrivateHandle *h)
{
if ( !h || !h->egl ) {
return;
}
if (__libEGL) {
__libEGL->eglTerminate(h->egl_dpy);
close_libegl();
}
h->egl_dpy = NULL;
h->egl = False;
}
*
* get_configs()
*
*
* Returns an array of EGL Frame Buffer Configuration Attributes for the
* given Display/Screen.
*
****/
static EGLConfigAttr *get_configs(const NvCtrlAttributePrivateHandle *h)
{
EGLConfig *configs = NULL;
EGLConfigAttr *cas = NULL;
int nconfigs;
int i;
EGLBoolean ret;
ret = (* (__libEGL->eglGetConfigs)) (h->egl_dpy, NULL, 0, &nconfigs);
if ( !ret ) {
goto fail;
}
configs = nvalloc((nconfigs + 1) * sizeof(EGLConfig));
cas = nvalloc((nconfigs + 1) * sizeof(EGLConfigAttr));
ret = (* (__libEGL->eglGetConfigs))(h->egl_dpy, configs, nconfigs,
&nconfigs);
for (i = 0; i < nconfigs; i++) {
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_RED_SIZE,
&cas[i].red_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_BLUE_SIZE,
&cas[i].blue_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_GREEN_SIZE,
&cas[i].green_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_DEPTH_SIZE,
&cas[i].depth_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_MAX_PBUFFER_WIDTH,
&cas[i].max_pbuffer_width);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_MAX_PBUFFER_HEIGHT,
&cas[i].max_pbuffer_height);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_MAX_PBUFFER_PIXELS,
&cas[i].max_pbuffer_pixels);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_ALPHA_SIZE,
&cas[i].alpha_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_ALPHA_MASK_SIZE,
&cas[i].alpha_mask_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_BIND_TO_TEXTURE_RGB,
&cas[i].bind_to_texture_rgb);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_BIND_TO_TEXTURE_RGBA,
&cas[i].bind_to_texture_rgba);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_BUFFER_SIZE,
&cas[i].buffer_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_COLOR_BUFFER_TYPE,
&cas[i].color_buffer_type);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_CONFIG_CAVEAT,
&cas[i].config_caveat);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_CONFIG_ID,
&cas[i].config_id);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_CONFORMANT,
&cas[i].conformant);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_LEVEL,
&cas[i].level);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_LUMINANCE_SIZE,
&cas[i].luminance_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_MAX_SWAP_INTERVAL,
&cas[i].max_swap_interval);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_MIN_SWAP_INTERVAL,
&cas[i].min_swap_interval);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_NATIVE_RENDERABLE,
&cas[i].native_renderable);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_NATIVE_VISUAL_ID,
&cas[i].native_visual_id);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_NATIVE_VISUAL_TYPE,
&cas[i].native_visual_type);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_RENDERABLE_TYPE,
&cas[i].renderable_type);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_SAMPLE_BUFFERS,
&cas[i].sample_buffers);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_SAMPLES,
&cas[i].samples);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_STENCIL_SIZE,
&cas[i].stencil_size);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_SURFACE_TYPE,
&cas[i].surface_type);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_TRANSPARENT_TYPE,
&cas[i].transparent_type);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_TRANSPARENT_RED_VALUE,
&cas[i].transparent_red_value);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_TRANSPARENT_GREEN_VALUE,
&cas[i].transparent_green_value);
if (!ret) goto fail;
ret = __libEGL->eglGetConfigAttrib(h->egl_dpy, configs[i],
EGL_TRANSPARENT_BLUE_VALUE,
&cas[i].transparent_blue_value);
if (!ret) goto fail;
}
free(configs);
return cas;
fail:
free(configs);
free(cas);
return NULL;
}
*
* NvCtrlEglGetVoidAttribute()
*
* Retrieves various EGL attributes (other than strings and ints)
*
****/
ReturnStatus NvCtrlEglGetVoidAttribute(const NvCtrlAttributePrivateHandle *h,
unsigned int display_mask,
int attr, void **ptr)
{
EGLConfigAttr *config_attribs = NULL;
if ( !h || !h->egl_dpy) {
return NvCtrlBadHandle;
}
if ( !h->egl || !__libEGL ) {
return NvCtrlMissingExtension;
}
if ( !ptr ) {
return NvCtrlBadArgument;
}
switch ( attr ) {
case NV_CTRL_ATTR_EGL_CONFIG_ATTRIBS:
config_attribs = get_configs(h);
*ptr = config_attribs;
break;
default:
return NvCtrlNoAttribute;
}
if ( *ptr == NULL ) {
return NvCtrlError;
}
return NvCtrlSuccess;
}
*
* NvCtrlEglGetStringAttribute()
*
* Retrieves a particular EGL information string by calling the appropriate
* function.
*/
ReturnStatus NvCtrlEglGetStringAttribute(const NvCtrlAttributePrivateHandle *h,
unsigned int display_mask,
int attr, char **ptr)
{
const char *str = NULL;
if ( !h || !h->egl_dpy) {
return NvCtrlBadHandle;
}
if ( !h->egl || !__libEGL ) {
return NvCtrlMissingExtension;
}
if ( !ptr ) {
return NvCtrlBadArgument;
}
switch (attr) {
case NV_CTRL_STRING_EGL_VENDOR:
str = __libEGL->eglQueryString(h->egl_dpy, EGL_VENDOR);
break;
case NV_CTRL_STRING_EGL_VERSION:
str = __libEGL->eglQueryString(h->egl_dpy, EGL_VERSION);
break;
case NV_CTRL_STRING_EGL_EXTENSIONS:
str = __libEGL->eglQueryString(h->egl_dpy, EGL_EXTENSIONS);
break;
default:
return NvCtrlNoAttribute;
}
if ( !str || (*ptr = strdup(str)) == NULL ) {
return NvCtrlError;
}
return NvCtrlSuccess;
}