如何将 gtkmm 与 EGL 结合使用

How to use gtkmm with EGL

我发现 this 博客 post 有一个关于如何将 EGL 与 GTK 结合使用的示例。但是我在我的项目中使用 gtkmm,因此我需要找到如何使用它

我需要找到这些函数:

gdk_x11_display_get_xdisplay
gtk_widget_get_display
gdk_x11_window_get_xid
gtk_widget_get_window
gtk_widget_get_allocated_width
gtk_widget_get_allocated_height

在 gtkmm 上。他们的 gtkmm 可能 return class 实例,所以我需要弄清楚如何获得这些 classes 指向的 C 对象以及

如果我们look at the GTK functions,来看个例子:

Display*    gdk_x11_display_get_xdisplay ()

它 return 是 Display*。同时,在 gtkmm for Display 中我们看到 gobj() return 是 C 对象 GdkDisplay*:

GdkDisplay*     gobj ()

这不是同一个对象。

那么,如何找到这些函数的 gtkmm 版本呢?

更新2:

根据评论中的建议,我做了一个最小可复现的例子:

#include <iostream>
#include <gtkmm.h>
#include <epoxy/gl.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
class MyOpenGLArea : public Gtk::Window
{
public:
    MyOpenGLArea()
    {
        set_title("Test");
        set_default_size(640, 360);

        add(vBox);

        glArea.set_hexpand(true);
        glArea.set_vexpand(true);
        glArea.set_auto_render(true);
        vBox.add(glArea);

        glArea.signal_realize().connect(sigc::mem_fun(*this, &MyOpenGLArea::realize));
        glArea.signal_render().connect(sigc::mem_fun(*this, &MyOpenGLArea::render), false);

        glArea.show();
        vBox.show();
    };

public:
    Gtk::GLArea glArea;
    Gtk::Box vBox{Gtk::ORIENTATION_VERTICAL, false};

    void realize()
    {
        EGLBoolean eglStatus;
        EGLConfig eglConfig;
        EGLint n_config;
        EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};

        eglDisplay = eglGetDisplay((EGLNativeDisplayType)gdk_x11_display_get_xdisplay(glArea.get_display()->gobj()));

        eglStatus = eglInitialize(eglDisplay, NULL, NULL);
        if (!eglStatus)
        {
            printf("Error at eglInitialize\n");
            switch (eglStatus)
            {
            case EGL_BAD_DISPLAY:
                printf("EGL_BAD_DISPLAY\n");
                break;
            case EGL_NOT_INITIALIZED:
                printf("EGL_NOT_INITIALIZED\n");
                break;
            case EGL_FALSE:
                printf("EGL_FALSE\n");
                break;
            }
        }
        eglStatus = eglChooseConfig(eglDisplay, context_attribs, &eglConfig, 1, &numConfigs);
        if (!eglStatus)
        {
            printf("Error at eglChooseConfig\n");
            switch (eglStatus)
            {
            case EGL_BAD_DISPLAY:
                printf("EGL_BAD_DISPLAY\n");
                break;
            case EGL_BAD_ATTRIBUTE:
                printf("EGL_BAD_ATTRIBUTE\n");
                break;
            case EGL_NOT_INITIALIZED:
                printf("EGL_NOT_INITIALIZED\n");
                break;
            case EGL_BAD_PARAMETER:
                printf("EGL_BAD_PARAMETER\n");
                break;
            case EGL_FALSE:
                printf("EGL_FALSE\n");
                break;
            }
        }
    };

    virtual bool render(const Glib::RefPtr<Gdk::GLContext> &context)
    {
        glDraw();
        glFinish();
        return true;
    }

    void glDraw()
    {
    }

private:
    EGLDisplay eglDisplay;
    EGLSurface eglSurface;
    EGLContext eglContext;
    int numConfigs;
};

int main(int argc, char **argv)
{
    auto app = Gtk::Application::create(argc, argv, "");
    MyOpenGLArea myOpenGLArea;
    return app->run(myOpenGLArea);
}

这是输出:

libEGL warning: DRI2: failed to authenticate
Error at eglChooseConfig
EGL_FALSE

我得到的显示仍然不正确

根据https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/

the OpenGL support inside GTK+ requires core GL profiles, and thus it won’t work with the fixed pipeline API that was common until OpenGL 3.2 and later versions. this means that you won’t be able to use API like glRotatef(), or glBegin()/glEnd() pairs, or any of that stuff.

所以您需要切换到使用可编程管线(即着色器,以及所有需要的)才能开始使用 Gtk::GLArea 小部件。

I need to find these functions:

gdk_x11_display_get_xdisplay
gtk_widget_get_display
gdk_x11_window_get_xid
gtk_widget_get_window
gtk_widget_get_allocated_width
gtk_widget_get_allocated_height

on gtkmm.

其中一些在 gtkmm 中有很容易找到的包装器。毕竟有一个命名系统。名为“gtk_<thing>_<action>”的 GTK 函数通常对应于 Gtk 命名空间中(大写的)<Thing> class 的 <action> 方法——即 Gtk::<Thing>::<action>.

这就剩下 X11 交互了。我不知道 GDK "x11" 部分的 C++ 包装器,因此您可能需要 mix C and C++ APIs。请注意几个名称相似的 classes。例如,Gtk::WindowGdk::Window 是不同的 class。此外,Display(没有名称空间)和 GdkDisplay 是不同的 classes。 (特别是,Display 既不是 GTK 的一部分,也不是 GDK 的一部分;它是 X11 的一部分。)

根据系统应该如何工作(意味着我还没有测试过),下面几行应该是从 gtkmm 调用 GDK 的 X11 交互函数的方法。这些假设变量已声明为 Gtk::GLArea glArea,例如示例代码中的数据成员。

gdk_x11_display_get_xdisplay(glArea.get_display()->gobj());
gdk_x11_window_get_xid(glArea.get_window()->gobj());

get_display 方法 returns 一个指向 Gdk::Display 的智能指针。调用指向对象的 gobj 方法会得到一个 GdkDisplay*,然后可以将其提供给 gdk_x11_display_get_xdisplay。类似地,get_window returns 一个指向 Gdk::Window 的智能指针,可以将其转换为指向 gdk_x11_window_get_xid.

的 C 对象的指针