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