Почему поверхность egl pixmap работает с opengl es, но не с opengl?

Я использую EGL с Xlib и OpenGL. Пока рисовал прямо в окне, все было нормально. Теперь я пытаюсь использовать растровые изображения в качестве поверхности EGL, но OpenGL вообще этого не меняет.

Я очищаю фон синим цветом с помощью OpenGL. Вот что я получаю вместо этого:

Корзина

Вот минимальный пример, демонстрирующий проблему (рисование этого мусора).

ОБНОВЛЕНИЕ: я добавил проверку ошибок и обнаружил, что eglCopyBuffers производит EGL_BAD_NATIVE_PIXMAP. Документы говорят, что это может произойти в двух случаях. : если реализация не поддерживает собственные растровые изображения или если аргумент нативного растрового изображения недействителен. Оба они кажутся маловероятными. Если я могу создать поверхность растрового изображения без ошибок, я считаю, что реализация поддерживает нативные растровые изображения. если я могу рисовать на растровом изображении, используя собственные методы, такие как XFillRectangle, я считаю, что растровое изображение является допустимым.

ОБНОВЛЕНИЕ: я запускаю это на ноутбуке с Ubuntu Gnome. У него две видеокарты: Intel HD Graphics 5500 (драйвер = i915) и Nvidia GeForce 920m (драйвер = nvidia). Основные строки из вывода es2_info (

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

Код:

// 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");
    }
}

person Nolan    schedule 06.09.2017    source источник
comment
Вы убедились, что eglCreatePixmapSurface() не возвращает EGL_NO_SURFACE? «Потому что это то, что он возвращает на моей стабильной машине Debian.   -  person genpfault    schedule 07.09.2017
comment
Ни один из атрибутов attrib_list не действителен для eglCreatePixmapSurface() согласно документы.   -  person genpfault    schedule 07.09.2017
comment
Это работает в моей системе.   -  person genpfault    schedule 07.09.2017
comment
@genpfault он действительно вернул EGL_NO_SURFACE. Однако изменение attrib_list на NULL не решило проблему. И ваш код не работает в моей системе, что заставляет меня думать, что проблема в библиотеке, а не в моем коде.   -  person Nolan    schedule 07.09.2017
comment
@genpfault Я добавил проверку ошибок. Они показали eglCopyBuffers неудачу. Я обновил вопрос с подробностями.   -  person Nolan    schedule 07.09.2017
comment
На чем вы пытаетесь это запустить? Обычный Linux (Debian / Ubuntu / CentOS / и т. Д.)? Что-нибудь необычное, вроде Raspberry Pi? Неудобная встроенная ... штука? Видеокарта и драйвер? Что дает es2_info?   -  person genpfault    schedule 07.09.2017
comment
@genpfault вопрос обновлен   -  person Nolan    schedule 07.09.2017


Ответы (1)


Оказывается, eglBindApi(EGL_OPENGL_API) является источником проблемы. Когда вы удалите один, вы получите синий квадрат, как и ожидалось.

По умолчанию EGL использует OpenGL ES в качестве API рендеринга и просто не работает с API рендеринга OpenGL. Мне не удалось найти ни одного примера кода, который использует EGL с API рендеринга OpenGL, но я нашел этот ответ. Это заставляет меня думать, что EGL не должен работать с OpenGL, хотя eglBindApi(EGL_OPENGL_API) не возвращает EGL_BAD_PARAMETER, который должен быть возвращен в соответствии с docs", если указанный клиентский API не поддерживается реализацией EGL ".

Поэтому я не принимаю это как ответ, потому что фактическая причина, по которой установка OpenGL в качестве API рендеринга нарушает код, все еще неизвестна.

person Nolan    schedule 30.12.2017