qemu/ui/egl-helpers.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include <glob.h>
   3#include <dirent.h>
   4
   5#include "ui/egl-helpers.h"
   6
   7EGLDisplay *qemu_egl_display;
   8EGLConfig qemu_egl_config;
   9
  10/* ---------------------------------------------------------------------- */
  11
  12static bool egl_gles;
  13static int egl_debug;
  14
  15#define egl_dbg(_x ...)                          \
  16    do {                                         \
  17        if (egl_debug) {                         \
  18            fprintf(stderr, "egl: " _x);         \
  19        }                                        \
  20    } while (0);
  21
  22/* ---------------------------------------------------------------------- */
  23
  24#ifdef CONFIG_OPENGL_DMABUF
  25
  26int qemu_egl_rn_fd;
  27struct gbm_device *qemu_egl_rn_gbm_dev;
  28EGLContext qemu_egl_rn_ctx;
  29
  30int qemu_egl_rendernode_open(void)
  31{
  32    DIR *dir;
  33    struct dirent *e;
  34    int r, fd;
  35    char *p;
  36
  37    dir = opendir("/dev/dri");
  38    if (!dir) {
  39        return -1;
  40    }
  41
  42    fd = -1;
  43    while ((e = readdir(dir))) {
  44        if (e->d_type != DT_CHR) {
  45            continue;
  46        }
  47
  48        if (strncmp(e->d_name, "renderD", 7)) {
  49            continue;
  50        }
  51
  52        r = asprintf(&p, "/dev/dri/%s", e->d_name);
  53        if (r < 0) {
  54            return -1;
  55        }
  56
  57        r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
  58        if (r < 0) {
  59            free(p);
  60            continue;
  61        }
  62        fd = r;
  63        free(p);
  64        break;
  65    }
  66
  67    closedir(dir);
  68    if (fd < 0) {
  69        return -1;
  70    }
  71    return fd;
  72}
  73
  74int egl_rendernode_init(void)
  75{
  76    qemu_egl_rn_fd = -1;
  77
  78    qemu_egl_rn_fd = qemu_egl_rendernode_open();
  79    if (qemu_egl_rn_fd == -1) {
  80        fprintf(stderr, "egl: no drm render node available\n");
  81        goto err;
  82    }
  83
  84    qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd);
  85    if (!qemu_egl_rn_gbm_dev) {
  86        fprintf(stderr, "egl: gbm_create_device failed\n");
  87        goto err;
  88    }
  89
  90    qemu_egl_init_dpy((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, false, false);
  91
  92    if (!epoxy_has_egl_extension(qemu_egl_display,
  93                                 "EGL_KHR_surfaceless_context")) {
  94        fprintf(stderr, "egl: EGL_KHR_surfaceless_context not supported\n");
  95        goto err;
  96    }
  97    if (!epoxy_has_egl_extension(qemu_egl_display,
  98                                 "EGL_MESA_image_dma_buf_export")) {
  99        fprintf(stderr, "egl: EGL_MESA_image_dma_buf_export not supported\n");
 100        goto err;
 101    }
 102
 103    qemu_egl_rn_ctx = qemu_egl_init_ctx();
 104    if (!qemu_egl_rn_ctx) {
 105        fprintf(stderr, "egl: egl_init_ctx failed\n");
 106        goto err;
 107    }
 108
 109    return 0;
 110
 111err:
 112    if (qemu_egl_rn_gbm_dev) {
 113        gbm_device_destroy(qemu_egl_rn_gbm_dev);
 114    }
 115    if (qemu_egl_rn_fd != -1) {
 116        close(qemu_egl_rn_fd);
 117    }
 118
 119    return -1;
 120}
 121
 122int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc)
 123{
 124    EGLImageKHR image;
 125    EGLint num_planes, fd;
 126
 127    image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
 128                              EGL_GL_TEXTURE_2D_KHR,
 129                              (EGLClientBuffer)(unsigned long)tex_id,
 130                              NULL);
 131    if (!image) {
 132        return -1;
 133    }
 134
 135    eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc,
 136                                  &num_planes, NULL);
 137    if (num_planes != 1) {
 138        eglDestroyImageKHR(qemu_egl_display, image);
 139        return -1;
 140    }
 141    eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL);
 142    eglDestroyImageKHR(qemu_egl_display, image);
 143
 144    return fd;
 145}
 146
 147#endif /* CONFIG_OPENGL_DMABUF */
 148
 149/* ---------------------------------------------------------------------- */
 150
 151EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
 152{
 153    EGLSurface esurface;
 154    EGLBoolean b;
 155
 156    egl_dbg("eglCreateWindowSurface (x11 win id 0x%lx) ...\n",
 157            (unsigned long) win);
 158    esurface = eglCreateWindowSurface(qemu_egl_display,
 159                                      qemu_egl_config,
 160                                      (EGLNativeWindowType)win, NULL);
 161    if (esurface == EGL_NO_SURFACE) {
 162        fprintf(stderr, "egl: eglCreateWindowSurface failed\n");
 163        return NULL;
 164    }
 165
 166    b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
 167    if (b == EGL_FALSE) {
 168        fprintf(stderr, "egl: eglMakeCurrent failed\n");
 169        return NULL;
 170    }
 171
 172    return esurface;
 173}
 174
 175/* ---------------------------------------------------------------------- */
 176
 177int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
 178{
 179    static const EGLint conf_att_gl[] = {
 180        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
 181        EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
 182        EGL_RED_SIZE,   5,
 183        EGL_GREEN_SIZE, 5,
 184        EGL_BLUE_SIZE,  5,
 185        EGL_ALPHA_SIZE, 0,
 186        EGL_NONE,
 187    };
 188    static const EGLint conf_att_gles[] = {
 189        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
 190        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
 191        EGL_RED_SIZE,   5,
 192        EGL_GREEN_SIZE, 5,
 193        EGL_BLUE_SIZE,  5,
 194        EGL_ALPHA_SIZE, 0,
 195        EGL_NONE,
 196    };
 197    EGLint major, minor;
 198    EGLBoolean b;
 199    EGLint n;
 200
 201    if (debug) {
 202        egl_debug = 1;
 203        setenv("EGL_LOG_LEVEL", "debug", true);
 204        setenv("LIBGL_DEBUG", "verbose", true);
 205    }
 206
 207    egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy);
 208    qemu_egl_display = eglGetDisplay(dpy);
 209    if (qemu_egl_display == EGL_NO_DISPLAY) {
 210        fprintf(stderr, "egl: eglGetDisplay failed\n");
 211        return -1;
 212    }
 213
 214    egl_dbg("eglInitialize ...\n");
 215    b = eglInitialize(qemu_egl_display, &major, &minor);
 216    if (b == EGL_FALSE) {
 217        fprintf(stderr, "egl: eglInitialize failed\n");
 218        return -1;
 219    }
 220
 221    egl_dbg("eglBindAPI ...\n");
 222    b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
 223    if (b == EGL_FALSE) {
 224        fprintf(stderr, "egl: eglBindAPI failed\n");
 225        return -1;
 226    }
 227
 228    egl_dbg("eglChooseConfig ...\n");
 229    b = eglChooseConfig(qemu_egl_display,
 230                        gles ? conf_att_gles : conf_att_gl,
 231                        &qemu_egl_config, 1, &n);
 232    if (b == EGL_FALSE || n != 1) {
 233        fprintf(stderr, "egl: eglChooseConfig failed\n");
 234        return -1;
 235    }
 236
 237    egl_gles = gles;
 238    return 0;
 239}
 240
 241EGLContext qemu_egl_init_ctx(void)
 242{
 243    static const EGLint ctx_att_gl[] = {
 244        EGL_NONE
 245    };
 246    static const EGLint ctx_att_gles[] = {
 247        EGL_CONTEXT_CLIENT_VERSION, 2,
 248        EGL_NONE
 249    };
 250
 251    EGLContext ectx;
 252    EGLBoolean b;
 253
 254    egl_dbg("eglCreateContext ...\n");
 255    ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
 256                            egl_gles ? ctx_att_gles : ctx_att_gl);
 257    if (ectx == EGL_NO_CONTEXT) {
 258        fprintf(stderr, "egl: eglCreateContext failed\n");
 259        return NULL;
 260    }
 261
 262    b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx);
 263    if (b == EGL_FALSE) {
 264        fprintf(stderr, "egl: eglMakeCurrent failed\n");
 265        return NULL;
 266    }
 267
 268    return ectx;
 269}
 270