Name

    MESA_platform_gbm

Name Strings

    EGL_MESA_platform_gbm

Contributors

    Chad Versace <chad.versace@intel.com>
    Kristian Høgsberg <krh@bitplanet.org>

Contacts

    Chad Versace <chad.versace@intel.com>

Status

    Complete

Version

    Version 7, 2016/01/04

Number

    EGL Extension #62

Extension Type

    EGL client extension

Dependencies

    Requires EGL_EXT_client_extensions to query its existence without
    a display.

    Requires EGL_EXT_platform_base.

    This extension is written against the wording of version 7 of the
    EGL_EXT_platform_base specification.

Overview

    This extension defines how to create EGL resources from native GBM
    resources using the functions defined by EGL_EXT_platform_base. (GBM is
    a Generic Buffer Manager for Linux).

New Types

    None

New Procedures and Functions

    None

New Tokens

    Accepted as the <platform> argument of eglGetPlatformDisplayEXT:

        EGL_PLATFORM_GBM_MESA                    0x31D7

Additions to the EGL Specification

    None.

New Behavior

    To determine if the EGL implementation supports this extension, clients
    should query the EGL_EXTENSIONS string of EGL_NO_DISPLAY.

    To obtain an EGLDisplay from an GBM device, call eglGetPlatformDisplayEXT with
    <platform> set to EGL_PLATFORM_GBM_MESA. The <native_display> parameter
    specifies the GBM device to use and must either point to a `struct
    gbm_device` or be NULL. If <native_display> is NULL, then the resultant
    EGLDisplay will be backed by some implementation-chosen GBM device.

    For each EGLConfig that belongs to the GBM platform, the
    EGL_NATIVE_VISUAL_ID attribute is a GBM color format, such as
    GBM_FORMAT_XRGB8888.

    To obtain a rendering surface from a GBM surface, call
    eglCreatePlatformWindowSurfaceEXT with a <dpy> that belongs to the GBM
    platform and a <native_window> that points to a `struct gbm_surface`.  If
    <native_window> was created without the GBM_BO_USE_RENDERING flag, or if
    the color format of <native_window> differs from the EGL_NATIVE_VISUAL_ID
    of <config>, then the function fails and generates EGL_BAD_MATCH.

    It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy> that
    belongs to the GBM platform. Any such call fails and generates
    EGL_BAD_PARAMETER.

Issues

    1. Should this extension permit NULL as input to eglGetPlatformDisplayEXT?

       RESOLUTION: Yes. When given NULL, eglGetPlatformDisplayEXT returns an
       EGLDisplay backed by an implementation-chosen GBM device.

Example Code

    // This example program creates an EGL surface from a GBM surface.
    //
    // If the macro EGL_MESA_platform_gbm is defined, then the program
    // creates the surfaces using the methods defined in this specification.
    // Otherwise, it uses the methods defined by the EGL 1.4 specification.
    //
    // Compile with `cc -std=c99 example.c -lgbm -lEGL`.

    #include <stdlib.h>
    #include <string.h>

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    #include <EGL/egl.h>
    #include <gbm.h>

    struct my_display {
        struct gbm_device *gbm;
        EGLDisplay egl;
    };

    struct my_config {
        struct my_display dpy;
        EGLConfig egl;
    };

    struct my_window {
        struct my_config config;
        struct gbm_surface *gbm;
        EGLSurface egl;
    };

    static void
    check_extensions(void)
    {
    #ifdef EGL_MESA_platform_gbm
        const char *client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);

        if (!client_extensions) {
            // EGL_EXT_client_extensions is unsupported.
            abort();
        }
        if (!strstr(client_extensions, "EGL_MESA_platform_gbm")) {
            abort();
        }
    #endif
    }

    static struct my_display
    get_display(void)
    {
        struct my_display dpy;

        int fd = open("/dev/dri/card0", O_RDWR | FD_CLOEXEC);
        if (fd < 0) {
            abort();
        }

        dpy.gbm = gbm_create_device(fd);
        if (!dpy.gbm) {
            abort();
        }


    #ifdef EGL_MESA_platform_gbm
        dpy.egl = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, dpy.gbm, NULL);
    #else
        dpy.egl = eglGetDisplay(dpy.gbm);
    #endif

        if (dpy.egl == EGL_NO_DISPLAY) {
            abort();
        }

        EGLint major, minor;
        if (!eglInitialize(dpy.egl, &major, &minor)) {
            abort();
        }

        return dpy;
    }

    static struct my_config
    get_config(struct my_display dpy)
    {
        struct my_config config = {
            .dpy = dpy,
        };

        EGLint egl_config_attribs[] = {
            EGL_BUFFER_SIZE,        32,
            EGL_DEPTH_SIZE,         EGL_DONT_CARE,
            EGL_STENCIL_SIZE,       EGL_DONT_CARE,
            EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
            EGL_NONE,
        };

        EGLint num_configs;
        if (!eglGetConfigs(dpy.egl, NULL, 0, &num_configs)) {
            abort();
        }

        EGLConfig *configs = malloc(num_configs * sizeof(EGLConfig));
        if (!eglChooseConfig(dpy.egl, egl_config_attribs,
                             configs, num_configs, &num_configs)) {
            abort();
        }
        if (num_configs == 0) {
            abort();
        }

        // Find a config whose native visual ID is the desired GBM format.
        for (int i = 0; i < num_configs; ++i) {
            EGLint gbm_format;

            if (!eglGetConfigAttrib(dpy.egl, configs[i],
                                    EGL_NATIVE_VISUAL_ID, &gbm_format)) {
                abort();
            }

            if (gbm_format == GBM_FORMAT_XRGB8888) {
                config.egl = configs[i];
                free(configs);
                return config;
            }
        }

        // Failed to find a config with matching GBM format.
        abort();
    }

    static struct my_window
    get_window(struct my_config config)
    {
        struct my_window window = {
            .config = config,
        };

        window.gbm = gbm_surface_create(config.dpy.gbm,
                                        256, 256,
                                        GBM_FORMAT_XRGB8888,
                                        GBM_BO_USE_RENDERING);
        if (!window.gbm) {
            abort();
        }

    #ifdef EGL_MESA_platform_gbm
        window.egl = eglCreatePlatformWindowSurfaceEXT(config.dpy.egl,
                                                       config.egl,
                                                       window.gbm,
                                                       NULL);
    #else
        window.egl = eglCreateWindowSurface(config.dpy.egl,
                                            config.egl,
                                            window.gbm,
                                            NULL);
    #endif

        if (window.egl == EGL_NO_SURFACE) {
            abort();
        }

        return window;
    }

    int
    main(void)
    {
        check_extensions();

        struct my_display dpy = get_display();
        struct my_config config = get_config(dpy);
        struct my_window window = get_window(config);

        return 0;
    }

Revision History

    Version 8, 2018-05-25 (Krzysztof Kosiński)
        - Corrected EGL_DEFAULT_DISPLAY to NULL. The second argument to
          eglGetPlatformDisplayEXT has type void*, while EGL_DEFAULT_DISPLAY has
          type EGLNativeDisplayType, which is not guaranteed to be convertible
          to void* - it could be int, long or intptr_t.

    Version 7, 2016-01-04 (Jon Leech)
        - Free config memory allocated in sample code (Public Bug 1445).

    Version 6, 2014-02-12 (Chad Versace)
        - Change resolution of issue #1 from "no" to "yes". Now
          eglGetPlatformDisplayEXT accepts EGL_DEFAULT_DISPLAY for GBM.

    Version 5, 2013-010-15 (Chad Versace)
        - Specify that EGL_NATIVE_VISUAL_ID is a GBM color format.
        - Require for eglCreatePlatformWindowSurfaceEXT that the GBM color
          format not differ between the EGLConfig and gbm_surface. (Suggested
          by Kristian).
        - Update example code to find matching EGL_NATIVE_VISUAL_ID.

    Version 4, 2013-09-13 (Chad Versace)
        - Update the text and example code to wording of version 7 of
          EGL_EXT_platform_base spec.
        - Add section "Extension Type".
        - Resolve issue #1 to "No".
        - Add issue #2.

    Version 3, 2013-04-26 (Chad Versace)
        - Add missing MESA suffix to new token.

    Version 2, 2013-04-23 (Chad Versace)
        - Add issue #1 regarding EGL_DEFAULT_DISPLAY.

    Version 1, 2013.03.24 (Chad Versace)
        - First draft
