Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/video_output/opengl/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 25 kB image not shown  

Quelle  egl.c   Sprache: C

 

/**
 * @file egl.c
 * @brief EGL OpenGL extension module
 */

/*****************************************************************************
 * Copyright © 2010-2014 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>
#include <assert.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#include <vlc_common.h>
#include <vlc_threads.h>
#include <vlc_plugin.h>
#include <vlc_opengl.h>
#include <vlc_window.h>
#ifdef USE_PLATFORM_X11
# include <vlc_xlib.h>
# include <X11/Xutil.h>
#endif
#ifdef USE_PLATFORM_XCB
# include <xcb/xcb.h>
# include "../xcb/events.h"
#endif
#ifdef USE_PLATFORM_WAYLAND
# include <wayland-egl.h>
#endif
#if defined (USE_PLATFORM_ANDROID)
# include "../android/utils.h"
#endif

static const char *clientExts;
#ifdef EGL_EXT_platform_base
static PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT;
static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createPlatformWindowSurfaceEXT;
#endif

typedef struct vlc_gl_sys_t
{
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
#if defined (USE_PLATFORM_X11)
    Display *x11;
    unsigned long x11_black_pixel;
    Window x11_win;
#endif
#if defined (USE_PLATFORM_XCB)
    xcb_connection_t *conn;
    uint32_t xcb_black_pixel;
    xcb_window_t xcb_win;
#endif
#if defined (USE_PLATFORM_WAYLAND)
    struct wl_egl_window *window;
#endif
    bool is_current;
} vlc_gl_sys_t;

static bool CheckAPI(EGLDisplay dpy, const char *api)
{
    const char *apis = eglQueryString(dpy, EGL_CLIENT_APIS);
    return vlc_gl_StrHasToken(apis, api);
}

static bool CheckClientExt(const char *name)
{
    return vlc_gl_StrHasToken(clientExts, name);
}

static bool CheckDisplayExt(EGLDisplay display, const char *name)
{
    const char *exts = eglQueryString(display, EGL_EXTENSIONS);
    return vlc_gl_StrHasToken(exts, name);
}

static void LogDeviceInfo(vlc_gl_t *gl,
                          PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT,
                          EGLDeviceEXT device)
{
    const char *device_ext = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS);
    if (device_ext == NULL)
        device_ext = "";

    /* EGL_EXT_device_query_name is a device extension, so it must be tested
     * against the device's own extension string, not the client one. */

    if (vlc_gl_StrHasToken(device_ext, "EGL_EXT_device_query_name"))
    {
        const char *vendor = eglQueryDeviceStringEXT(device, EGL_VENDOR);
        const char *renderer = eglQueryDeviceStringEXT(device, EGL_RENDERER_EXT);
        msg_Dbg(gl, "   vendor='%s' renderer='%s'",
                vendor ? vendor : "unknown", renderer ? renderer : "unknown");
    }

    msg_Dbg(gl, "   extensions: %s", device_ext);

    if (vlc_gl_StrHasToken(device_ext, "EGL_EXT_device_drm"))
    {
        const char *path = eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT);
        if (path != NULL)
            msg_Dbg(gl, "   drm device: %s", path);
    }
    if (vlc_gl_StrHasToken(device_ext, "EGL_EXT_device_drm_render_node"))
    {
        const char *path = eglQueryDeviceStringEXT(device, EGL_DRM_RENDER_NODE_FILE_EXT);
        if (path != NULL)
            msg_Dbg(gl, "   drm render node: %s", path);
    }
}

static void DisplayAvailableDevices(vlc_gl_t *gl)
{
    PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
        (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
    PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT =
        (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT");

    EGLint device_count = 0;
    if (eglQueryDevicesEXT(0, NULL, &device_count) != EGL_TRUE
     || device_count <= 0)
    {
        msg_Dbg(gl, "could not enumerate EGL devices");
        return;
    }

    EGLDeviceEXT *devices = vlc_alloc(device_count, sizeof(*devices));
    if (devices == NULL)
        return;

    if (eglQueryDevicesEXT(device_count, devices, &device_count) != EGL_TRUE)
    {
        free(devices);
        return;
    }

    msg_Dbg(gl, "EGL has %d devices:", device_count);
    for (EGLint i = 0; i < device_count; ++i)
    {
        msg_Dbg(gl, " - device %d:", i);
        LogDeviceInfo(gl, eglQueryDeviceStringEXT, devices[i]);
    }

    free(devices);
}

struct gl_api
{
   const char name[10];
   EGLenum    api;
   EGLint     min_minor;
   EGLint     render_bit;
   EGLint     attr[3];
};

static int MakeCurrent (vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
                        sys->context) != EGL_TRUE)
        return VLC_EGENERIC;
    sys->is_current = true;
    return VLC_SUCCESS;
}

static void ReleaseCurrent (vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                    EGL_NO_CONTEXT);
    sys->is_current = false;
}

#ifdef USE_PLATFORM_WAYLAND
static void Resize (vlc_gl_t *gl, unsigned width, unsigned height)
{
    vlc_gl_sys_t *sys = gl->sys;

    wl_egl_window_resize(sys->window, width, height, 0, 0);
}

static void DestroySurface(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    wl_egl_window_destroy(sys->window);
}

static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
                                unsigned int width, unsigned int height)
{
    vlc_gl_sys_t *sys = gl->sys;
    EGLSurface surface;

    sys->window = wl_egl_window_create(gl->surface->handle.wl, width, height);
    if (sys->window == NULL)
        return EGL_NO_SURFACE;

# if defined(EGL_VERSION_1_5)
    assert(CheckClientExt("EGL_KHR_platform_wayland"));
    surface = eglCreatePlatformWindowSurface(dpy, config, sys->window, NULL);

# elif defined(EGL_EXT_platform_base)
    assert(CheckClientExt("EGL_EXT_platform_wayland"));
    surface = createPlatformWindowSurfaceEXT(dpy, config, sys->window, NULL);

# else
    surface = EGL_NO_SURFACE;
# endif

    if (surface == EGL_NO_SURFACE)
        wl_egl_window_destroy(sys->window);

    return surface;
}

static void ReleaseDisplay(vlc_gl_t *gl)
{
    (void) gl;
}

static EGLDisplay OpenDisplay(vlc_gl_t *gl)
{
    vlc_window_t *surface = gl->surface;

    if (surface->type != VLC_WINDOW_TYPE_WAYLAND)
        return EGL_NO_DISPLAY;
    if (!CheckClientExt("EGL_KHR_display_reference")) {
        msg_Warn(gl, "EGL display reference counting not supported");
        return EGL_NO_DISPLAY;
    }

# ifdef EGL_KHR_display_reference
    static const EGLAttrib attrs[] = {
        EGL_TRACK_REFERENCES_KHR, EGL_TRUE,
        EGL_NONE
    };

#  if defined(EGL_VERSION_1_5)
#   ifdef EGL_KHR_platform_wayland
    if (CheckClientExt("EGL_KHR_platform_wayland"))
        return eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR,
                                     surface->display.wl, attrs);
#   endif

#  elif defined(EGL_EXT_platform_wayland)
    if (CheckClientExt("EGL_EXT_platform_wayland"))
        return getPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT,
                                     surface->display.wl, attrs);
#  endif
# endif
    return EGL_NO_DISPLAY;
}

#elif defined(USE_PLATFORM_X11)
static void Resize (vlc_gl_t *gl, unsigned width, unsigned height)
{
    vlc_gl_sys_t *sys = gl->sys;
    EGLint val;

    EGLDisplay old_display = eglGetCurrentDisplay();
    EGLSurface old_draw = eglGetCurrentSurface(EGL_DRAW);
    EGLSurface old_read = eglGetCurrentSurface(EGL_READ);
    EGLContext old_ctx = eglGetCurrentContext();

    bool made_current = eglMakeCurrent(sys->display, sys->surface, sys->surface, sys->context);
    if (made_current)
        eglWaitClient();

    unsigned long init_serial = LastKnownRequestProcessed(sys->x11);
    unsigned long resize_serial = NextRequest(sys->x11);
    XResizeWindow(sys->x11, sys->x11_win, width, height);

    if (made_current)
    {
        eglQuerySurface(sys->display, sys->surface, EGL_HEIGHT, &val); /* force Mesa to see new size in time for next draw */
        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
        if (old_display != EGL_NO_DISPLAY)
            eglMakeCurrent(old_display, old_draw, old_read, old_ctx);
        else
            eglMakeCurrent(sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    }
    if (LastKnownRequestProcessed(sys->x11) - init_serial < resize_serial - init_serial)
        XSync(sys->x11, False);
}

static void DestroySurface(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    XUnmapWindow(sys->x11, sys->x11_win);
}

static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
                                unsigned int width, unsigned int height)
{
    vlc_gl_sys_t *sys = gl->sys;

    EGLint val;
    if (eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE)
        return EGL_NO_SURFACE;
    XVisualInfo vinfo_template;
    int vinfoc;
    vinfo_template.visualid = (VisualID) val;
    XVisualInfo *vinfov = XGetVisualInfo(sys->x11, VisualIDMask, &vinfo_template, &vinfoc);
    if (vinfov == NULL || vinfoc == 0)
        return EGL_NO_SURFACE;
    Visual *visual = vinfov[0].visual;
    int depth = vinfov[0].depth;
    XFree(vinfov);

    unsigned long mask =
        CWBackPixel | CWBorderPixel | CWBitGravity | CWColormap;
    XSetWindowAttributes swa = {
        .background_pixel = sys->x11_black_pixel,
        .border_pixel = sys->x11_black_pixel,
        .bit_gravity = NorthWestGravity,
        .colormap = XCreateColormap(sys->x11, gl->surface->handle.xid, visual,
                                    AllocNone),
    };
    Window win = XCreateWindow(sys->x11, gl->surface->handle.xid, 0, 0, width,
                               height, 0, depth, InputOutput, visual, mask,
                               &swa);
    sys->x11_win = win;
    XMapWindow(sys->x11, win);

# if defined(EGL_VERSION_1_5)
    if (CheckClientExt("EGL_KHR_platform_x11"))
        return eglCreatePlatformWindowSurface(dpy, config, &win, NULL);

# elif defined(EGL_EXT_platform_base)
    if (CheckClientExt("EGL_EXT_platform_x11"))
        return createPlatformWindowSurfaceEXT(dpy, config, &win, NULL);

# endif
    return eglCreateWindowSurface(dpy, config, win, NULL);
}

static void ReleaseDisplay(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    XCloseDisplay(sys->x11);
}

static EGLDisplay OpenDisplay(vlc_gl_t *gl)
{
    vlc_window_t *surface = gl->surface;
    vlc_gl_sys_t *sys = gl->sys;

    if (surface->type != VLC_WINDOW_TYPE_XID || !vlc_xlib_init(VLC_OBJECT(gl)))
        return EGL_NO_DISPLAY;

    Display *x11 = XOpenDisplay(surface->display.x11);
    if (x11 == NULL)
        return EGL_NO_DISPLAY;

    XWindowAttributes wa;

    if (!XGetWindowAttributes(x11, surface->handle.xid, &wa))
        goto error;

    EGLDisplay display;
    int snum = XScreenNumberOfScreen(wa.screen);

# if defined(EGL_VERSION_1_5)
#  ifdef EGL_KHR_paltform_x11
    if (CheckClientExt("EGL_KHR_platform_x11")) {
        const EGLAttrib attrs[] = {
            EGL_PLATFORM_X11_SCREEN_KHR, snum,
            EGL_NONE
        };

        display = getPlatformDisplayEXT(EGL_PLATFORM_X11_KHR, x11, attrs);
    } else
#  endif
# elif defined(EGL_EXT_platform_x11)
    if (CheckClientExt("EGL_EXT_platform_x11")) {
        const EGLint attrs[] = {
            EGL_PLATFORM_X11_SCREEN_EXT, snum,
            EGL_NONE
        };

        display = getPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, x11, attrs);
    } else
# endif
# ifdef __unix__
    if (snum == XDefaultScreen(x11))
        display = eglGetDisplay(x11);
    else
# endif
        display = EGL_NO_DISPLAY;

    if (display == EGL_NO_DISPLAY)
        goto error;

    sys->x11 = x11;
    sys->x11_black_pixel = BlackPixelOfScreen(wa.screen);
    return display;
error:
    XCloseDisplay(x11);
    return EGL_NO_DISPLAY;
}

#elif defined(USE_PLATFORM_XCB)
static int GetScreenNum(xcb_connection_t *conn, const xcb_screen_t *scr)
{
    xcb_screen_iterator_t i = xcb_setup_roots_iterator(xcb_get_setup(conn));
    int n = 0;

    while (scr != i.data) {
         xcb_screen_next(&i);
         n++;
    }
    return n;
}

static void Resize (vlc_gl_t *gl, unsigned width, unsigned height)
{
    vlc_gl_sys_t *sys = gl->sys;
    EGLint val;

    EGLDisplay old_display = eglGetCurrentDisplay();
    EGLSurface old_draw = eglGetCurrentSurface(EGL_DRAW);
    EGLSurface old_read = eglGetCurrentSurface(EGL_READ);
    EGLContext old_ctx = eglGetCurrentContext();

    bool made_current = eglMakeCurrent(sys->display, sys->surface, sys->surface, sys->context);
    if (made_current)
        eglWaitClient();

    uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
    const uint32_t values[] = { width, height };
    xcb_void_cookie_t cookie = xcb_configure_window_checked(sys->conn, sys->xcb_win, mask, values);

    if (made_current)
    {
        eglQuerySurface(sys->display, sys->surface, EGL_HEIGHT, &val); /* force Mesa to see new size in time for next draw */
        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
        if (old_display != EGL_NO_DISPLAY)
            eglMakeCurrent(old_display, old_draw, old_read, old_ctx);
        else
            eglMakeCurrent(sys->display, NULL, NULL, NULL);
    }
    free(xcb_request_check(sys->conn, cookie));
}

static void DestroySurface(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    xcb_unmap_window(sys->conn, sys->xcb_win);
}

static uint8_t VisualIdToDepth(xcb_connection_t *conn, xcb_visualid_t vid)
{
    xcb_screen_iterator_t si = xcb_setup_roots_iterator (xcb_get_setup (conn));
    for (; si.rem; xcb_screen_next (&si)) {
        xcb_depth_iterator_t di = xcb_screen_allowed_depths_iterator (si.data);
        for (; di.rem; xcb_depth_next (&di)) {
            xcb_visualtype_iterator_t vi = xcb_depth_visuals_iterator (di.data);
            for (; vi.rem; xcb_visualtype_next (&vi)) {
                if (vid == vi.data->visual_id) {
                    return di.data->depth;
                }
            }
        }
    }
    return 0;
}

static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
                                unsigned int width, unsigned int height)
{
# ifdef EGL_EXT_platform_base
    vlc_gl_sys_t *sys = gl->sys;
    xcb_connection_t *conn = sys->conn;

    EGLint val;
    if (eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE)
        return EGL_NO_SURFACE;
    xcb_visualid_t vid = (xcb_visualid_t) val;
    xcb_colormap_t cmap = xcb_generate_id(conn);
    xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE,
                        cmap, gl->surface->handle.xid, vid);
    uint8_t depth = VisualIdToDepth(conn, vid);
    if (depth == 0)
        return EGL_NO_SURFACE;

    xcb_window_t win = xcb_generate_id(conn);
    uint32_t mask =
        XCB_CW_BACK_PIXEL |
        XCB_CW_BORDER_PIXEL |
        XCB_CW_BIT_GRAVITY |
        XCB_CW_COLORMAP;
    const uint32_t values[] = {
        /* XCB_CW_BACK_PIXEL */
        sys->xcb_black_pixel,
        /* XCB_CW_BORDER_PIXEL */
        sys->xcb_black_pixel,
        /* XCB_CW_BIT_GRAVITY */
        XCB_GRAVITY_NORTH_WEST,
        /* XCB_CW_COLORMAP */
        cmap,
    };
    xcb_create_window(conn, depth, win, gl->surface->handle.xid, 0, 0,
                      width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, vid,
                      mask, values);
    xcb_map_window(conn, win);
    sys->xcb_win = win;

    assert(CheckClientExt("EGL_EXT_platform_xcb"));
    return createPlatformWindowSurfaceEXT(dpy, config, &win, NULL);
# else
    return EGL_NO_SURFACE;
# endif
}

static void ReleaseDisplay(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    xcb_disconnect(sys->conn);
}

static EGLDisplay OpenDisplay(vlc_gl_t *gl)
{
# ifdef EGL_EXT_platform_xcb
    vlc_window_t *surface = gl->surface;
    vlc_gl_sys_t *sys = gl->sys;
    xcb_connection_t *conn;
    const xcb_screen_t *scr;

    if (surface->type != VLC_WINDOW_TYPE_XID)
        return EGL_NO_DISPLAY;
    if (!CheckClientExt("EGL_EXT_platform_xcb"))
        return EGL_NO_DISPLAY;
    if (vlc_xcb_parent_Create(gl->obj.logger, surface, &conn,
                              &scr) != VLC_SUCCESS)
        return EGL_NO_DISPLAY;

    const EGLint attrs[] = {
        EGL_PLATFORM_XCB_SCREEN_EXT, GetScreenNum(conn, scr),
        EGL_NONE
    };

    EGLDisplay display = getPlatformDisplayEXT(EGL_PLATFORM_XCB_EXT, conn,
                                               attrs);
    if (display == EGL_NO_DISPLAY) {
        xcb_disconnect(conn);
        goto out;
    }

    sys->conn = conn;
    sys->xcb_black_pixel = scr->black_pixel;
out:
    return display;
# else
    return EGL_NO_DISPLAY;
# endif
}

#elif defined (USE_PLATFORM_ANDROID)
# define Resize (NULL)

static void DestroySurface(vlc_gl_t *gl)
{
    AWindowHandler_releaseANativeWindow(gl->surface->display.anativewindow,
                                        gl->surface->handle.android_id);
}

static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
                                unsigned int width, unsigned int height)
{
    ANativeWindow *anw =
        AWindowHandler_getANativeWindow(gl->surface->display.anativewindow,
                                        gl->surface->handle.android_id);

    if (anw == NULL)
        return EGL_NO_SURFACE;

    int awh_caps = AWindowHandler_getCapabilities(gl->surface->display.anativewindow);
    if ((awh_caps & AWH_CAPS_SURFACE_VIEW) == 0)
    {
        ANativeWindow_setBuffersGeometry(anw, width, height, AHARDWAREBUFFER_FORMAT_BLOB);
    }

    return eglCreateWindowSurface(dpy, config, anw, NULL);
}

static void ReleaseDisplay(vlc_gl_t *gl)
{
    (void) gl;
}

static EGLDisplay OpenDisplay(vlc_gl_t *gl)
{
# if defined (__ANDROID__) || defined (ANDROID)
    if (gl->surface->type == VLC_WINDOW_TYPE_ANDROID_NATIVE)
        return eglGetDisplay(EGL_DEFAULT_DISPLAY);
# endif
    return EGL_NO_DISPLAY;
}

#else
# define Resize (NULL)

static void DestroySurface(vlc_gl_t *gl)
{
    (void) gl;
}

static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
                                unsigned int width, unsigned int height)
{
    HWND window = gl->surface->handle.hwnd;

    (void) width; (void) height;
    return eglCreateWindowSurface(dpy, config, window, NULL);
}

static void ReleaseDisplay(vlc_gl_t *gl)
{
    (void) gl;
}

static EGLDisplay OpenDisplay(vlc_gl_t *gl)
{
# if defined (_WIN32) || defined (__VC32__) \
  && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__)
    if (gl->surface->type == VLC_WINDOW_TYPE_HWND)
        return eglGetDisplay(EGL_DEFAULT_DISPLAY);
# endif
    return EGL_NO_DISPLAY;
}
#endif

static void SwapBuffers (vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    if (!sys->is_current)
    {
        EGLDisplay previous_display = eglGetCurrentDisplay();
        EGLSurface s_read = eglGetCurrentSurface(EGL_READ);
        EGLSurface s_draw = eglGetCurrentSurface(EGL_DRAW);
        EGLContext previous_context = eglGetCurrentContext();

        eglMakeCurrent(sys->display, sys->surface, sys->surface, sys->context);
        eglSwapBuffers (sys->display, sys->surface);
        if (previous_display != EGL_NO_DISPLAY)
            eglMakeCurrent(previous_display, s_draw, s_read, previous_context);
        else
            eglMakeCurrent(sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    }
    else
        eglSwapBuffers (sys->display, sys->surface);
}

static void *GetSymbol(vlc_gl_t *gl, const char *procname)
{
    (void) gl;
    return (void *)eglGetProcAddress (procname);
}

static void Close(vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    if (sys->context != EGL_NO_CONTEXT)
        eglDestroyContext(sys->display, sys->context);
    if (sys->surface != EGL_NO_SURFACE) {
        eglDestroySurface(sys->display, sys->surface);
        DestroySurface(gl);
    }
    eglTerminate(sys->display);
    ReleaseDisplay(gl);
    free (sys);
}

static void InitEGL(void)
{
    static vlc_once_t once = VLC_STATIC_ONCE;

    if (unlikely(!vlc_once_begin(&once))) {
        clientExts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
        if (!clientExts)
            clientExts = "";

#ifdef EGL_EXT_platform_base
        getPlatformDisplayEXT =
            (void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
        createPlatformWindowSurfaceEXT =
            (void *) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
#endif
        vlc_once_complete(&once);
    }
}

/**
 * Probe EGL display availability
 */

static int Open(vlc_gl_t *gl, const struct gl_api *api,
                unsigned width, unsigned height,
                const struct vlc_gl_cfg *gl_cfg)
{
    InitEGL();

    int ret = VLC_EGENERIC;
    vlc_object_t *obj = VLC_OBJECT(gl);
    vlc_gl_sys_t *sys = malloc(sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    msg_Dbg(obj, "EGL client extensions: %s", clientExts);

    gl->sys = sys;
    sys->display = EGL_NO_DISPLAY;
    sys->surface = EGL_NO_SURFACE;
    sys->context = EGL_NO_CONTEXT;
    sys->is_current = false;

    sys->display = OpenDisplay(gl);
    if (sys->display == EGL_NO_DISPLAY) {
        free(sys);
        return VLC_ENOTSUP;
    }

    /* Initialize EGL display */
    EGLint major, minor;
    if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
        goto error;
    msg_Dbg(obj, "EGL version %s by %s",
            eglQueryString(sys->display, EGL_VERSION),
            eglQueryString(sys->display, EGL_VENDOR));

    const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
    if (*ext)
        msg_Dbg(obj, "EGL display extensions: %s", ext);

    if (major != 1 || minor < api->min_minor
     || !CheckAPI(sys->display, api->name))
    {
        msg_Err(obj, "cannot select %s API", api->name);
        goto error;
    }

    bool has_device_enum = CheckClientExt("EGL_EXT_device_enumeration");
    bool has_device_query = CheckClientExt("EGL_EXT_device_query");

    if (has_device_query && has_device_enum)
    {
        DisplayAvailableDevices(gl);
        PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT =
            (PFNEGLQUERYDISPLAYATTRIBEXTPROC)eglGetProcAddress("eglQueryDisplayAttribEXT");
        PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT =
            (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT");

        EGLAttrib device_attr;
        if (eglQueryDisplayAttribEXT(sys->display, EGL_DEVICE_EXT,
                                     &device_attr) == EGL_TRUE)
        {
            EGLDeviceEXT device = (EGLDeviceEXT)device_attr;
            msg_Dbg(gl, "Using EGL device:");
            LogDeviceInfo(gl, eglQueryDeviceStringEXT, device);
        }
        else
            msg_Dbg(gl, "could not query the EGL device in use");
    }

    bool has_query_driver =
        CheckDisplayExt(sys->display, "EGL_MESA_query_driver");

    if (has_query_driver)
    {
        PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName =
            (PFNEGLGETDISPLAYDRIVERNAMEPROC) eglGetProcAddress("eglGetDisplayDriverName");
        const char *driver = eglGetDisplayDriverName(sys->display);
        msg_Dbg(gl, "Using EGL driver: %s", driver ? driver : "unknown");
    }
    else
        msg_Dbg(gl, "EGL_MESA_query_driver is unavailable");

    const EGLint conf_attr[] = {
        EGL_RED_SIZE, 5,
        EGL_GREEN_SIZE, 5,
        EGL_BLUE_SIZE, 5,
        EGL_ALPHA_SIZE, gl_cfg->need_alpha ? 5 : 0,
        EGL_RENDERABLE_TYPE, api->render_bit,
        EGL_NONE
    };
    EGLConfig cfgv[1];
    EGLint cfgc;

    if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
     || cfgc == 0)
    {
        msg_Err (obj, "cannot choose EGL configuration");
        goto error;
    }

    /* Create a drawing surface */
    sys->surface = CreateSurface(gl, sys->display, cfgv[0], width, height);
    if (sys->surface == EGL_NO_SURFACE)
    {
        msg_Err (obj, "cannot create EGL window surface");
        goto error;
    }

    if (eglBindAPI (api->api) != EGL_TRUE)
    {
        msg_Err (obj, "cannot bind EGL API");
        goto error;
    }

    EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
                                      api->attr);
    if (ctx == EGL_NO_CONTEXT)
    {
        msg_Err (obj, "cannot create EGL context");
        goto error;
    }
    sys->context = ctx;

    /* Initialize OpenGL callbacks */
    static const struct vlc_gl_operations ops =
    {
        .make_current = MakeCurrent,
        .release_current = ReleaseCurrent,
        .resize = Resize,
        .swap = SwapBuffers,
        .get_proc_address = GetSymbol,
        .close = Close,
    };
    gl->ops = &ops;

    return VLC_SUCCESS;

error:
    Close(gl);
    return ret;
}

static int OpenGLES2(vlc_gl_t *gl, unsigned width, unsigned height,
                     const struct vlc_gl_cfg *gl_cfg)
{
    static const struct gl_api api = {
        "OpenGL_ES", EGL_OPENGL_ES_API, 4, EGL_OPENGL_ES2_BIT,
        { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
    };
    return Open(gl, &api, width, height, gl_cfg);
}

static int OpenGL(vlc_gl_t *gl, unsigned width, unsigned height,
                  const struct vlc_gl_cfg *gl_cfg)
{
    static const struct gl_api api = {
        "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
        { EGL_NONE },
    };
    return Open(gl, &api, width, height, gl_cfg);
}

#ifdef USE_PLATFORM_XCB
# define VLC_PRIORITY 60
#endif
#ifndef VLC_PRIORITY
# define VLC_PRIORITY 50
#endif

vlc_module_begin ()
    set_shortname (N_("EGL"))
    set_description (N_("EGL extension for OpenGL"))
    set_subcategory (SUBCAT_VIDEO_VOUT)
    set_callback_opengl(OpenGL, VLC_PRIORITY)
    add_shortcut ("egl")

    add_submodule ()
    set_callback_opengl_es2(OpenGLES2, VLC_PRIORITY)
    add_shortcut ("egl")

vlc_module_end ()

Messung
CHZG
81979290

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.