OpenGL是否使用Xlib来绘制窗口并渲染事物,还是反过来?

éta*_*ogy 5 x11 opengl graphics fonts

我想使用OpenGLXlib在窗口上渲染字体和线条,但我想知道哪一个是"更基础".

使用Xlib接口,我可以用这样的东西(我在这里找到)来渲染这样的东西:

// gcc x_1.c -o x_1 -lX11 && ./x_1

#include <stdio.h>
#include <X11/Xlib.h>

// This program draws a red line and some text in a chosen font.
Display *display;
Window  window;
XSetWindowAttributes attributes;
XGCValues gr_values;
XFontStruct *fontinfo;
GC gr_context;
Visual *visual;
int depth;
int screen;
XEvent event;
XColor    color, dummy;

int main() {
     display = XOpenDisplay(NULL);
     screen = DefaultScreen(display);
     visual = DefaultVisual(display,screen);
     depth  = DefaultDepth(display,screen);
     attributes.background_pixel = XWhitePixel(display,screen);

     window = XCreateWindow( display,XRootWindow(display,screen),
                            200, 200, 350, 200, 5, depth,  InputOutput,
                            visual ,CWBackPixel, &attributes);
     XSelectInput(display,window,ExposureMask | KeyPressMask) ;
     fontinfo = XLoadQueryFont(display,"6x10");

     XAllocNamedColor(display, DefaultColormap(display, screen),"red",
                      &color,&dummy);

     gr_values.font = fontinfo->fid;
     gr_values.foreground = color.pixel;
     gr_context=XCreateGC(display,window,GCFont+GCForeground, &gr_values);
     XFlush(display);
     XMapWindow(display,window);
     XFlush(display);

     while(1){
        XNextEvent(display,&event);

        switch(event.type){
        case Expose:
             XDrawLine(display,window,gr_context,0,0, 100, 100);
             XDrawString(display,window,gr_context,100,100,"hello",5);
             break;
        case KeyPress:
             XCloseDisplay(display);
             return 1;

        }
     }
     return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以使用纯OpenGL代码完成同样的事情,这引发了一些问题.

OpenGL是否使用Xlib来显示窗口并渲染字体/几何图元?或者是周围的其他方式?

如果我想对渲染和显示进行更多"低级"控制,我应该使用哪一个?


编辑:

我的目标应用程序是一个准系统文本编辑器,它只渲染位图字体,只有255种颜色,并且只进行软件渲染(即假设没有GPU存在).

我尝试过Cairo/Pango,SDL2,GTKQt,但与纯Xlib相比,它们很慢且反应迟钝.

dat*_*olf 15

警告:文字墙进来了!

@sourcejedi已经给出了答案,但其中有一些不准确之处 - 这并不会造成伤害,但可能会令人困惑.

首先,OpenGL和Xlib彼此正交.两者都不依赖于另一个,你可以独立使用它们.GLX对Xlib 一种依赖(这就是为什么你不能完全抛弃Xlib而不是Xcb,如果你想要GLX),但是这个依赖的表面区域足够小,所以你可以使用Xcb大多数情况下,使用Xlib-on-Xcb包装器来处理必须使用GLX的部分.现在我在这里删除了一些缩略语,所以让我们先对它们进行分类:

Xlib和Xcb都是实现X11协议客户端的库.从技术上讲,你可以通过实现"你自己"的协议与没有它们的X11服务器通信(事实上,正在不断努力从同样的规范文件中自动生成Haskell代码,这些代码文件也用于生成Xcb代码).X11是通过套接字传输的,所以如果你能以某种方式转移那个套接字和绑定之间的某些内部状态,你甚至可以混合和匹配绑定,如果你小心你去哪里.

OpenGL本身是一个纯粹的低级别(它提供的基本意义上的低级别:点,线和三角形)绘图工具,并且它没有"窗口"的概念.通过引入framebuffer对象,原则上您可以创建无头OpenGL上下文并完全在自我管理的图像表面的范围内操作.但是经常(但肯定不总是)你希望你的图画能够立即显示在显示器上.这就是窗口系统接口(WSI)发挥作用的地方.OpenGL因此围绕它的整个支持结构已经很老了,所以对整个WSI业务并没有太多的考虑,这导致了一个相当好的......实际上根本没有完全定义的接口,到目前为止这一切都发生在环境中.通常的方法是"在这里我有一些预先存在的显示系统的图像表面,我可以在那上面隐藏OpenGL吗?" 这让我们看到了OpenGL的相当临时的窗口系统API.用于X11的GLX和用于Win32的WGL; Apple是它自己的整个章节......

GLX是两件事:首先它是X11扩展,即它使用X11传输为X11服务器中的一组新命令创建一个通道.这些命令是版本1.1到2.1中指定的OpenGL函数(尚未为3.x向前指定GLX).在这方面,GLX在X11服务器端放置一个OpenGL实现,GLX操作码用于向运行服务器端的OpenGL上下文进行远程过程调用.其次是一个GLX客户端实现,它位于libGL.soOpenGL API访问库中.

除此之外,GLX还实现了一些"便利"功能,比如从X11服务器端字体创建OpenGL显示列表的rasterop"字体"; 仅适用于以前使用X11核心的旧版位图字体.在低像素密度显示器上没有抗锯齿并且看起来不是特别好(如果你有一个高像素密度输出设备,你可以在没有抗锯齿的情况下离开,高分辨率位图字体实际上看起来非常好,例如:激光打印机).WGL遵循GLX的领先优势,并为Windows位图字体做了同样的事情.这是直接构建在OpenGL生态系统中的唯一"种类"字体渲染支持.但是对于7位可打印ASCII集之外的任何东西都没用.它完全没有布局引擎来正确格式化文本(左,右,中心对齐,对齐或其他).它完全依赖于显示列表和OpenGL光栅操作,这些操作有一些注意事项,如果第一个字符的起始位置恰好位于视口之外,整个事情都不会起作用".所以不要打扰甚至尝试使用它.

使用GLX,您可以使用现有的X11窗口并发送设置此窗口的X11服务器命令以与OpenGL一起使用.同样使用GLX,您可以发送X11服务器命令,要求它创建OpenGL上下文.OpenGL上下文与特定的X11 drawable无关.您可以自由地附加和分离它,只要您打算附加它的drawable 与该上下文兼容(即已针对特定的framebuffer格式进行配置,该上下文期望其主帧缓冲区).然后,当您进行OpenGL调用时,GLX将它们包装到操作码中,并通过套接字连接将它们发送到执行它们的X11服务器.

当然,所有这些去/序列化都会产生一些非显着的执行成本,因此很快就引入了一种称为"直接上下文"的特殊模式,其中GLX/X11服务器组合仅用于设置OpenGL上下文并使其成为当前X11 drawables,其余程序直接针对OpenGL实现,从而避免了所有序列化,甚至可以直接访问大量数据对象(纹理,缓冲对象等)所在的地址空间.这就是为什么在基于X11的环境中,您可以找到实际出现在两个进程中的相同直接连接上下文的OpenGL实现实例:X11服务器和使用它的客户端.

正如我上面提到的Xlib,Xcb&co只是X11协议的客户端实现.X11的服务器端提供了一组基本的图形功能.X11核心具有一些有限的位图字体绘制功能,以及绘制点,线,弧,(圆角)矩形,圆和多边形的功能.用实心笔或阴影图案进行绘图和填充; 没有插值或渐变.根据您想要绘制的图像类型,这是相当有限的.在2000年到2010年之间,每个人都想画出色彩丰富的用户界面,有很多渐变和花哨的边框等等(个人我从来不喜欢这些),但在过去几年中,半/平面UI设计已经成为一种趋势,你可以实际绘制的与X11核心(没有抗锯齿文本).最终人们希望能够绘制渐变X11方面,因此引入了XRender扩展,它为您提供了基本上相当于OpenGL的GL_TRIANGLES基元的2D,没有着色器,纹理和照明; 你会得到颜色插值,渐变和抗锯齿.作为一个侧面的Xft库(重要的,这是一个库,而不是X11服务器的东西),创建了捎带XRender将一堆客户端光栅化字体字形加载到服务器,以便您可以将其与可绘制的"抗锯齿" "文字.这是关于X11服务器的绘图功能.如何在X11服务器中实际实现这些绘图功能是未指定的,完全取决于实现,更重要的是依赖于依赖于设备的X代码(DDX),即X图形驱动程序!它可以完全用软件完成(通常情况下,目前通过基于pixman渲染库的服务器端组件),但GPU加速甚至基于所使用的OpenGL实现(魅力)的服务器端部分.

如果我想对渲染和显示进行更多"低级"控制,我应该使用哪一个?

这完全取决于您的目标应用程序.

如果你的目标是做一些没有做很多图形图形(文本编辑器,聊天程序等)的东西,你可以与X11绑定,然后可能是X11到Xlib或Xcb.最重要的是,X11为您提供了一些假装是中途合理的文本绘图功能的东西,至少以可预测的方式工作.

如果您的目标是进行图形图形处理(图像处理,CAD,桌面出版,还有Web浏览器),OpenGL是正确的选择,但这意味着您可以"自己"处理超出分数,线条的任何事情和三角形.

这些天,实际上存在GPU.10年前,并没有那么多,所以当时开发的UI工具包和图形后端(我们仍然在使用它们)将完全用软件在CPU上完成大部分工作,并将最终图像传输到显示器设备.这是合理的.如果最终目标是可再现的,高质量的图形仍然是,因为GPU为性能削减了很多角落并且行为不同(OpenGL要求在同一上下文中渲染相同操作链的结果为1:1匹配,但只改变一位,他们所有的赌注都关闭).

这些天你可以在现代Linux(!)系统上找到的三个渲染库(一般不是X11!)并且可以单独使用的是Cairo,Anti-Grain-Geometry(AGG)pixman.Cairo主要由基于GDK/GTK +的程序使用,pixman在X11服务器中使用(但您也可以在程序中使用它).AGG特别是没有工具包的主要图形工具包,但是被许多程序和库使用(最值得注意的是绘图,如matplotlib).人们也不能忘记Qt中的"光栅"图形引擎,但是它只能在QPainter中的Qt中使用(如果你的程序使用Qt,那么它是独立的,但如果没有Qt则不能使用).

谈到AGG与开罗,开罗的最大卖点是,它有一个纯粹的C绑定.不幸的是,开罗不是一个非常快速的渲染器(它在过去10年取得了巨大进步).但是它正在吃掉AGG的尘埃,它更快,而且(具有讽刺意味)也能产生更好的质量; 不幸的是AGG是一个C++库,所以为了有效地使用它,你必然会使用C++,这是一个缺点.几年前,AGG的主要开发人员黯然离世,这使得开发停滞了一段时间,但它再次被社区所接受.


éta*_*ogy 7

简短答案(从使用 Xlib/XCB/GLX/OpenGL 推断)和Youtube 教程

  • Xlib是X 协议(客户端)的高级 C 包装器。
  • XCB是围绕X 协议(客户端)的低级 C 扭曲器。
  • X窗口系统作为“客户端-服务器”系统工作,其中“X 服务器”是 GPU,“X 客户端”是您的应用程序。
  • X 客户端和 X 服务器使用 X 协议通过套接字向彼此发送请求/回复/错误/事件(每个 32 字节长?)
  • GLX既是一个协议扩展,也是一个API,它将 X Window 系统连接到 OpenGL,并允许 X 资源(例如 X 窗口或 X 像素图)用于 OpenGL 调用。
  • OpenGL是一种图形API,它将绘制/内存命令发送到 GPU。它在通常称为 的共享库中实现libGL.so,对于 NVIDIA,该共享库是由 NVIDIA 实现的。
  • 在进行第一个 OpenGL 调用之前,OpenGL 应用程序需要X 显示/连接X 屏幕X 窗口(或GLX 窗口)、X 颜色图GLX fbconfigGLX 上下文。OpenGL 调用的结果随后渲染在 X 窗口(或 GLX 窗口)上。
  • Linux内核DRIDRMKMS,它们似乎比 Xlib/XCB/GLX/OpenGL 级别低,并且对它们完全不可见(接近 GPU 驱动程序的级别;实际上我认为 NVIDIA驱动程序可能会绕过大部分内核基础设施?)。

因此,Xlib/XCB 创建窗口,然后OpenGL 渲染它们

(OpenGL无法创建窗口。Xlib/XCB可以渲染,但我不认为它与GPU加速相关。)