简体   繁体   中英

Why egl pixmap surface works with opengl es but not with opengl?

I use EGL with Xlib and OpenGL. While I was drawing straight on the window everything was fine. Now I'm trying to use pixmaps as EGL surface but OpenGL doesn't change it at all.

I clean the background with the blue color using OpenGL. Here's what I get instead:

垃圾

Here's minimal example demonstaiting the problem(drawing this trash).

UPDATE: I added error checks and find out that eglCopyBuffers produces EGL_BAD_NATIVE_PIXMAP . Docs tell this can happen in two cases: if implementation doesn't support native pixmaps or if native pixmap argument is not valid. They both seem unlikely. If I can create pixmap surface without error I believe implementation supports native pixmaps. if I can draw on the pixmap using native methods like XFillRectangle I believe pixmap is valid.

UPDATE: I'm running this on a laptop with Ubuntu Gnome. It has two video cards: Intel HD Graphics 5500(driver=i915) and Nvidia GeForce 920m(driver=nvidia). Main lines from es2_info output( full version ):

EGL_VERSION: 1.4
EGL_VENDOR: NVIDIA
EGL_CLIENT_APIS: OpenGL_ES OpenGL
GL_VERSION: OpenGL ES 3.2 NVIDIA 375.66
GL_RENDERER: GeForce 920M/PCIe/SSE2

Code:

// main.c
// cc main.c -lX11 -lEGL -lGL
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <EGL/egl.h>
#include <X11/Xlib.h>

void
die(const char * errstr, ...) {
    va_list ap;
    va_start(ap, errstr);
    vfprintf(stderr, errstr, ap);
    va_end(ap);
    exit(1);
}

int main() {
    Display * display = XOpenDisplay(NULL);
    if (!display) die("Can't create xlib display.\n");
    int screen = XDefaultScreen(display);
    GC gc = XDefaultGC(display, screen);
    Window root_window = XRootWindow(display, screen);
    unsigned long black_pixel = XBlackPixel(display, screen);
    unsigned long white_pixel = XWhitePixel(display, screen);
    Window window = XCreateSimpleWindow(display, root_window, 0, 0, 640, 480,
        0, black_pixel, white_pixel);
    if (!window) die("Can't create window.\n");
    int res = XSelectInput(display, window, ExposureMask);
    if (!res) die("XSelectInput failed.\n");
    Pixmap pixmap = XCreatePixmap(display, window, 400, 400, 24);
    if (!pixmap) die("Can't create pixmap.\n");
    EGLDisplay egldisplay = eglGetDisplay(display);
    if (EGL_NO_DISPLAY == egldisplay) die("Can't cate egl display.\n");
    res = eglInitialize(egldisplay, NULL, NULL);
    if (!res) die("eglInitialize failed.\n");
    EGLConfig config;
    int num_configs;
    static int attrib_list[] = {
        EGL_RED_SIZE,           8,
        EGL_GREEN_SIZE,         8,
        EGL_BLUE_SIZE,          8,
        EGL_ALPHA_SIZE,         0,
        EGL_RENDERABLE_TYPE,    EGL_OPENGL_BIT,
        EGL_SURFACE_TYPE,       EGL_PIXMAP_BIT,
        EGL_NONE
    };
    res = eglChooseConfig(egldisplay, attrib_list, &config, 1, &num_configs);
    if (!res) die("eglChooseConfig failed.\n");
    if (0 == num_configs) die("No appropriate egl config found.\n");
    EGLSurface surface =
        eglCreatePixmapSurface(egldisplay, config, pixmap, NULL);
    if (EGL_NO_SURFACE == surface) die("Can't create egl pixmap surface.\n");
    res = eglBindAPI(EGL_OPENGL_API);
    if (!res) die("eglBindApi failed.\n");
    EGLContext context =
        eglCreateContext(egldisplay, config, EGL_NO_CONTEXT, NULL);
    if (EGL_NO_CONTEXT == config) die("Can't create egl context.\n");
    res = eglMakeCurrent(egldisplay, surface, surface, context);
    if (!res) die("eglMakeCurrent failed.\n");
    res = XMapWindow(display, window);
    if (!res) die("XMapWindow failed.\n");
    while (1) {
        XEvent event;
        res = XNextEvent(display, &event);
        if (Expose != event.type) continue;
        glClearColor(0, 0, 1, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        glFinish();
        res = eglWaitGL();
        if (!res) die("eglWaitGL failed.\n");
        res = XCopyArea(display, pixmap, window, gc, 0, 0, 400, 400, 0, 0);
        if (!res) die("XCopyArea failed.\n");
    }
}

Turns out eglBindApi(EGL_OPENGL_API) is source of the issue. When you delete one you get blue square as expected.

By default EGL uses OpenGL ES as rendering API and It simply doesn't work with OpenGL rendering API . I couldn't find single example of code that uses EGL with OpenGL rendering API but I found this answer. This makes me think EGL isn't supposed to work with OpenGL even though eglBindApi(EGL_OPENGL_API) doesn't return EGL_BAD_PARAMETER which must be returned accroding to docs "if the specified client API is not supported by the EGL implementation".

So I don't accept this as an answer because actual reason why setting OpenGL as rendering API breaks the code is still unknown.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM