如何在没有窗口管理器的情况下在Linux中使用OpenGL?

vlurs2pr  于 2023-10-18  发布在  Linux
关注(0)|答案(4)|浏览(193)

我刚读完LFS这本书,我的Linux系统现在正在工作。我想使用OpenGL在屏幕上显示图形,而现在唯一安装的软件包是http://www.linuxfromscratch.org/lfs/view/stable/chapter03/packages.html上描述的那些。
我不想安装Gnome、KDE或X.org之类的东西。相反,我想直接从我的软件中使用OpenGL。这可能吗?我该如何做?或者它就像写一个全屏运行的OpenGL应用程序一样容易(我不这么认为:'p')?

gc0ot86w

gc0ot86w1#

你不需要安装Gnome或KDE。这些用于管理窗口,您可以启动图形应用程序,而无需窗口管理器。
因此,您必须安装X服务器。X服务器负责在屏幕上绘制内容。没有X服务器,你就不能启动图形应用程序。
安装X之后,启动它,导出你的DISPLAY环境变量,剩下的就像写一个全屏运行的OpenGL应用程序一样:-)

2skhul33

2skhul332#

你也可以使用Pygame来创建自定义的启动UI。也可以尝试看看Wayland合成器,因为它已经取代了Fedora和Ubuntu等版本中的XServer。

h9a6wy2h

h9a6wy2h3#

kmscube DRM示例

https://github.com/robclark/kmscube
这可能是最流行的演示,它使用OpenGL和EGL。
不幸的是,Ubuntu 18.04包与NVIDIA专有驱动程序它不为我工作后进入Ctrl + Alt + F3:

drmModeGetResources failed: Invalid argument
failed to initialize legacy DRM

错误报告:https://github.com/robclark/kmscube/issues/12
但我在模拟器上运行了。
它占据了整个显示器,并显示了一个彩色旋转立方体。

l7wslrjt

l7wslrjt4#

您可以使用**SRM library (Simple Rendering Manager)**,这是一个C库,专为在KMS/DRM上下文中使用OpenGL ES 2.0进行渲染而设计。它的一个显著优点是它为您简化了所有DRM/KMS配置。此外,它还有助于从单个分配在多GPU设置中的GPU之间共享OpenGL纹理。
这里有一个基本的例子来说明如何使用它:

#include <SRMCore.h>
#include <SRMDevice.h>
#include <SRMConnector.h>
#include <SRMConnectorMode.h>
#include <SRMListener.h>

#include <SRMList.h>
#include <SRMLog.h>

#include <GLES2/gl2.h>

#include <math.h>
#include <fcntl.h>
#include <unistd.h>

float color = 0.f;

/* Opens a DRM device */
static int openRestricted(const char *path, int flags, void *userData)
{
    SRM_UNUSED(userData);

    // Here something like libseat could be used instead
    return open(path, flags);
}

/* Closes a DRM device */
static void closeRestricted(int fd, void *userData)
{
    SRM_UNUSED(userData);
    close(fd);
}

static SRMInterface srmInterface =
{
    .openRestricted = &openRestricted,
    .closeRestricted = &closeRestricted
};

static void initializeGL(SRMConnector *connector, void *userData)
{
    SRM_UNUSED(userData);

    /* You must not do any drawing here as it won't make it to
     * the screen. */

    SRMConnectorMode *mode = srmConnectorGetCurrentMode(connector);

    glViewport(0, 
               0, 
               srmConnectorModeGetWidth(mode), 
               srmConnectorModeGetHeight(mode));

    // Schedule a repaint (this eventually calls paintGL() later, not directly)
    srmConnectorRepaint(connector);
}

static void paintGL(SRMConnector *connector, void *userData)
{
    SRM_UNUSED(userData);

    glClearColor((sinf(color) + 1.f) / 2.f,
                 (sinf(color * 0.5f) + 1.f) / 2.f,
                 (sinf(color * 0.25f) + 1.f) / 2.f,
                 1.f);

    color += 0.01f;

    if (color > M_PI*4.f)
        color = 0.f;

    glClear(GL_COLOR_BUFFER_BIT);
    srmConnectorRepaint(connector);
}

static void resizeGL(SRMConnector *connector, void *userData)
{
    /* You must not do any drawing here as it won't make it to
     * the screen.
     * This is called when the connector changes its current mode,
     * set with srmConnectorSetMode() */

    // Reuse initializeGL() as it only sets the viewport
    initializeGL(connector, userData);
}

static void pageFlipped(SRMConnector *connector, void *userData)
{
    SRM_UNUSED(connector);
    SRM_UNUSED(userData);

    /* You must not do any drawing here as it won't make it to
     * the screen.
     * This is called when the last rendered frame is now being
     * displayed on screen.
     * Google v-sync for more info. */
}

static void uninitializeGL(SRMConnector *connector, void *userData)
{
    SRM_UNUSED(connector);
    SRM_UNUSED(userData);

    /* You must not do any drawing here as it won't make it to
     * the screen.
     * Here you should free any resource created on initializeGL()
     * like shaders, programs, textures, etc. */
}

static SRMConnectorInterface connectorInterface =
{
    .initializeGL = &initializeGL,
    .paintGL = &paintGL,
    .resizeGL = &resizeGL,
    .pageFlipped = &pageFlipped,
    .uninitializeGL = &uninitializeGL
};

static void connectorPluggedEventHandler(SRMListener *listener, SRMConnector *connector)
{
    SRM_UNUSED(listener);

    /* This is called when a new connector is avaliable (E.g. Plugging an HDMI display). */

    /* Got a new connector, let's render on it */
    if (!srmConnectorInitialize(connector, &connectorInterface, NULL))
        SRMError("[srm-basic] Failed to initialize connector %s.",
                 srmConnectorGetModel(connector));
}

static void connectorUnpluggedEventHandler(SRMListener *listener, SRMConnector *connector)
{
    SRM_UNUSED(listener);
    SRM_UNUSED(connector);

    /* This is called when a connector is no longer avaliable (E.g. Unplugging an HDMI display). */

    /* The connnector is automatically uninitialized after this event (if initialized)
     * so calling srmConnectorUninitialize() is a no-op. */
}

int main(void)
{
    SRMCore *core = srmCoreCreate(&srmInterface, NULL);

    if (!core)
    {
        SRMFatal("[srm-basic] Failed to initialize SRM core.");
        return 1;
    }

    // Subscribe to Udev events
    SRMListener *connectorPluggedEventListener = srmCoreAddConnectorPluggedEventListener(core, &connectorPluggedEventHandler, NULL);
    SRMListener *connectorUnpluggedEventListener = srmCoreAddConnectorUnpluggedEventListener(core, &connectorUnpluggedEventHandler, NULL);

    // Find and initialize avaliable connectors

    // Loop each GPU (device)
    SRMListForeach (deviceIt, srmCoreGetDevices(core))
    {
        SRMDevice *device = srmListItemGetData(deviceIt);

        // Loop each GPU connector (screen)
        SRMListForeach (connectorIt, srmDeviceGetConnectors(device))
        {
            SRMConnector *connector = srmListItemGetData(connectorIt);

            if (srmConnectorIsConnected(connector))
            {
                if (!srmConnectorInitialize(connector, &connectorInterface, NULL))
                    SRMError("[srm-basic] Failed to initialize connector %s.",
                             srmConnectorGetModel(connector));
            }
        }
    }

    while (1)
    {
        /* Udev monitor poll DRM devices/connectors hotplugging events (-1 disables timeout).
         * To get a pollable FD use srmCoreGetMonitorFD() */

        if (srmCoreProccessMonitor(core, -1) < 0)
            break;
    }

    /* Unsubscribe to DRM events
     *
     * These listeners are automatically destroyed when calling srmCoreDestroy()
     * so there is no need to free them manually.
     * This is here just to show how to unsubscribe to events on the fly. */

    srmListenerDestroy(connectorPluggedEventListener);
    srmListenerDestroy(connectorUnpluggedEventListener);

    // Finish SRM
    srmCoreDestroy(core);

    return 0;
}

1.首先创建**SRMCore示例。
1.然后,通过每个
SRMDevice(GPU)进行计算。每个GPU都有一个SRMConnectors**(显示器)列表。
1.使用srmConnectorInitialize()初始化所需的连接器。
1.该库为每个连接器创建一个渲染线程,并调用典型的OpenGL事件,如 initializeGL()paintGL()resizeGL() 等。
1.要在连接器中计划新的重绘,请使用srmConnectorRepaint()。
1.如果您需要创建OpenGL纹理,请参考SRMBuffer documentation
我希望您发现这个库对您的特定用例有用。

相关问题