OpenGL 学习笔记 I:OpenGL glew glad glfw glut 的关系,OpenGL 状态机,现代操作系统的窗口管理器,OpenGL 窗口和上下文 OpenGL context

本文主要是介绍OpenGL 学习笔记 I:OpenGL glew glad glfw glut 的关系,OpenGL 状态机,现代操作系统的窗口管理器,OpenGL 窗口和上下文 OpenGL context,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本来想边速成 OpenGL 然后顺带复习图形学除了光线追踪部分来准备考试,但是考试推迟了,所以就不速成了。首先是一开始配环境遇到的各种问题,之前第一次学 OpenGL 照猫画虎复制老师给的源码画了line ,strip 多边形等的图形,实际没明白 OpenGL 到底是这么设计的,还有  glew glad glfw glut 这些东西也很多一笔带过要么说是解决一些 OpenGL 的附带问题,加载函数和绑定窗口。我没找到很具体的解释,所以还是自己亲自部署一下了。

对于这些理解,感觉源码面前了无秘密还是有必要的:这里有答主给了一个把 glad 和 glfw 全部工作都展开出来的代码(linux 下 的 xwindow):

glfw和glad有什么区别呢,glad是用来干什么的(只知道是一个库)? - 知乎 (zhihu.com)l

 Windows 平台的空 OpenGL 窗口创建的完整的代码这里也有:c++ - Initializing OpenGL without libraries - Stack Overflow,读者可以参照阅读。


复习编译与链接装载 - 动态链接与 PIC

  • PIC 是地址无关代码的意思。地址无关代码主要是在共享库里面的因为库的函数、变量地址都是运行时才能确定的。对于库自己内部的寻址由于可以直接用相对寻址,比如基于 PC 的相对 offset JMP 寻址。
  • 全局变量和共享依赖:但是对库里面又引用了其他的模块或者库以及每个调用程序用到的全局变量(必须独一份),都需要去查询他的调用地址(say 一个函数指针从而可以调用函数)。
  • 动态链接:GOT 表是全局位移表,通过这个表连接器在 elf(executable and linking file) 读入运行的时候装载。
  • 性能:这个动态库的运行是慢一点的(多一次间接寻址)。
  • Procedure Linkage table lazy load 提高程序的启动速度,但是这样 lazy binding 实际运行时可能会慢,但是没用到的不用 pay for it。
  • 编译方法:gcc -fPIC -shared a.c -o liba.so
  • 平滑升级:libxxx.so 和 libxxx.so.1和 libxxx.so.1.x 解释,是因为实际库是有版本的,Linux上对动态库的命名用libxxx.so.a.b.c的格式。然后 so 是软连接到 so.1,so.1 是软连接到 .so.1.x, 这样可以实现现场升级。如果 so 连接到 .1 的话,运行时可以升级到 .2,然后因为原来文件是软连接,所以可以保留 refcnt,新的程序可以运行 .2。实际更新动态库可以采用 rm 源文件然后新建一个,这样是两个 inode 互不影响。windows 的文件被占用无法删除就做不到这一点了。

接口、显卡驱动和 dlsym

  • Open GL 是接口与规范(spec):Khronos 是超原始神时空旅行者,他设计和规定 API,不指定实现。一开始的 1.1 版本经典地 shipeed with OS。其表现为为一个没有实现的头文件。在 windows 下是在 SDK 的 include 文件夹的 um/gl/gl.h,这里 um 是 user mode 的意思。(理论上应该在 GL/gl.h,但是历史原因 dos 不区分大小写)。gl.h 里面只有一些 macro 定义和 1.1 的经典 OpenGL 函数签名。但是没有实现,实现由显卡驱动完成。
  • 显卡驱动:由于图形学管线的东西不是简单的通用计算模型,硬件上也和 CPU 架构不一样(GPU Architecture 可以读 RTR4 Chapter23),每种不同的显卡版本的架构和他的操作也不一样,但是总的来说是支持各种基本的图形管线操作和各种新增特性的,所以没有 GPU 的汇编语言,GPU 厂家直接提供驱动,包括 Open GL、Direct X ,Vulkan 的 runtime library等。(OpenGL 某个版本之后不再进行维护,超原始神时空旅行者将会转向维护 Vulkan,作为 OpenGL 的现代替代品,他更加底层,驱动变薄,灵活度高)。
  • 链接库:由此可知实际编译 Open GL 程序必须要链接到显卡驱动提供的 libGL 库。一般显卡驱动安装后,会在 /usr/lib/ 下面创建一个软链接 libGL.so pointed to implementation.
  • OpenGL extension由于硬件的问题,而 linux 和 windows 系统都必须提供必要的向下兼容,对于旧版的显卡,如果驱动没有提供新版本 OpenGL 引入的,OpenGL 无法直接更新其 gl.h 接口,否则对于驱动(a.k.a. libGL.so)没有提供的,无法链接。所以都只能通过动态绑定来实现。extension 还能够支持类似 cpp TS 的功能,对于没有直接进入规范的 api,如果显卡厂商提供了,也能通过 extension 机制来实用。
  • dlsym linux 下(win 是 LoadLibrary)可以通过 dlsym 来 dynamic linking 在一个 so 文件(which is opened via dlopen)里面查询一个符号。通过这个,应用程序可以根据 OpenGL 1.1 之后的 spec 规定的函数名字或者一些显卡可能提供的 extension 来进行 glXXXX 函数的查询,如果有就不会返回 NULL,这种运行时查询机制比直接头文件全部指定一些可能不存在的函数要靠谱不少,而且也支持多文件查询,比如可以优先选择某个实现,如果不存在,就 fallback 到另一个实现上。
  • GDI 是什么?GDI  是微软的 graphics device interface。一般来说,GPU能做的事情 CPU 也能做。对于 2D 的东西来说,其实CPU也能胜任(漂亮的 GUI 会有很多浮点运算,不过如果不要太多炫酷效果,实际整数也够用了,想各自画图算法 Breshenham 都是整数算法),GPU主要是 3D 很厉害。

What is GLADGLEW

  • Loading library这两个都是上面说的,完成动态链接库的现场绑定的东西。
  • 同样的:glad 和 glew 做的事情是支持 OpenGL 1.1 之后的函数的动态加载,所以叫 loading library。
  • Which one更加新写的库,他和 glew 各自都有优点缺点,新程序可能都用 glad 了。但是注意的是 glew 和 glad 都支持最新版的 OpenGL(4.6)。glad 可以直接 ship,glew 可能要在系统 include 设置(以库提供)。

窗口化和 OpenGL 上下文(Context

  • 首先理解没有窗口化时期的 GUI早期的 OS 一般是单一的 console 输入输出对于 linux 下是怎么开机 init 和 login 的,之前  Proactor Reactor 模型 里面分析过了。这里主要要理解的 console、terminal(shell 就不用说了,shell 是一个处理文本命令转为 exec 或者 syscall 的程序,非GUI 的UI)。terminal 可以概括为是一套环境,包含文本 IO,或者说他是一个程序,负责 IO 与 shell 互动。
  • 显卡的 framebuffer OS 的显示缓冲区:实际,早期的系统其终端显示的字体是由显卡来实现的。这种模式在显卡上叫做文本模式。相对的是图形模式,图形模式的 framebuffer 就是一个分辨率(e.g. 4096*2160)的 2d-array,而文本模式,会根据字符大小宽度计算出最大行数和列数。所以说 DOS 游戏其实就是工作在像素模式,显存是像素。这也是为什么 dos 进游戏可能会黑屏一会儿,因为从文本模式转像素模式。而 window 进游戏是 window 窗口管理器直接把全屏缓冲区送 OpenGL 程序或者 Direct X 程序,所以换缓冲区可能会黑屏一小会,而窗口化不会但是窗口化还要走一层窗口管理器再渲染,性能变差。
  • Windows terminal但是如果走了窗口化的路子,就不能依赖显卡的文本模式了。我们查看最新的 UWP 应用 windows terminal  的源码(他是 CPP 写的,说是 GPU 绘制,好看快速)里面,renderer 有两个渲染器,一个是 GPU 的一个是 gdi based 。
  • 如何实现一个窗口管理器:比较抽象的方案是通过提供一整套组件库等上层抽象(WPF、win32 GUI 程序),比较底层的方案是提供一系列 frame buffer 的管理器。应用请求生成一个 window 的时候,就给他一个 framebuffer(OpenGL、Direct X 应用程序的方案)。对于窗口切换和 resize 等东西,都用事件驱动来做。每次通过计算激活窗口,进行 Z-buffer 遮挡测试,临时缓冲区等方案。还有 diff 等进行合并,以及添加阴影特效等。他很复杂是因为比如你开一个窗口一直需要实时更新的(比如一个计时器一直更新),就算他不是 active,也要实时渲染做 composition 的。每次鼠标移动窗口的时候,要重新做 z-buffer depth 测试。
  • OpenGL context这么一来,就能明白了,OpenGL 无法提供窗口管理的功能,这种东西一般都要 OS 提供。 Linux 下通过 x window 系统,window 下是 wgl。所以读者可以在上面的源码中看到一个是调用了 glx 的东西,一个是调用的 wgl 的东西,其实这些就是 OS 针对 OpenGL 做的一些窗口 handle 的抽象接口。窗口在 OpenGL context 的存在形式是一个 framebuffer 的描述信息。而用 context 本身是一个状态机模式,整个 OpenGL 就是一个巨大对象,操作不通过对象指针进行,而是全局的 context 指针,所以 Open GL 是通过 setContext 来切换所有函数的操作对象的。OpenGL 的函数也没有返回值,这个是经典的 C style 了,因为返回一个对象很复杂,所以一般用参数同时负责 in out。

What is GLFWGLU

  • glut 是 utility,他提供了上面说的创建窗口和上下文的事情,防止要自己做一堆脏活。还顺便把键盘鼠标这些和 windows /Linux 的窗口系统的事件负责的东西完成了。glut 还提供了画立体图形、茶壶等的函数,不用自己写 glBegin 和传顶点什么的。最后一次更新是很多年前。
  • glfw一个比较新的还在维护的库。It provides a simple API for creating windows, contexts and surfaces, receiving input and events. 他不止支持 OpenGL 还支持 Vulkan (不过 Vulkan 名义上是 OpenGL 的正统不向下兼容的后继)。

OpenGL 状态机

  • 不用指针:为了方便,OpenGL 用一种 id (GLuint)来表示他的对象,类似 Linux 下管理文件是通过 file descriptor,实际这些东西都是他自己内部来 malloc (只是比喻,实际是在 GPU 的缓存)好的。像顶点数据,以及缓冲区所以外面又套了一层 glGenBuffers、glDeleteBuffers 这些成对的东西。对我来说,永远支持 RAIIc++ - RAII wrapper for OpenGL objects - Stack Overflow
  • 缓冲区:GPU 与 CPU 的交互由于没有 UMA,这样程序必须通过 CPU (或者 DMA 类似的东西)往 GPU 传数据,所以像 Buffers 就是 GPU 的 buffer,至于什么时候传给 GPU 就看实现了。
  • BindOpenGL 的显卡上 Object 还真的很 C style 的,就是真的是 malloc + free + void* 的比喻,对于实际空间要设置为什么类型是通过宏来指定的,所以要 Bind 来指定类型,相当于是你还要给 void * 指定一个数据类型。
  • 为什么不用经典 OOP实际现在 core 模式的 OpenGL 是基于三角形、顶点数据以及 shader 来实现整个流程的,所以 OOP 的发挥没有意义。(当然是支持直线和各种多边形的,但是模型表示一般都用三角形顶点集合和片元集合,所以 OOP 没有什么意义,比如你 Triangle t = new Triangle 然后 draw,实际用途不大)。像 RAII wrapper for buffers 或者 textures 会优点意义,因为类似管理 malloc 和 free。

这篇关于OpenGL 学习笔记 I:OpenGL glew glad glfw glut 的关系,OpenGL 状态机,现代操作系统的窗口管理器,OpenGL 窗口和上下文 OpenGL context的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/970550

相关文章

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

龙蜥操作系统Anolis OS-23.x安装配置图解教程(保姆级)

《龙蜥操作系统AnolisOS-23.x安装配置图解教程(保姆级)》:本文主要介绍了安装和配置AnolisOS23.2系统,包括分区、软件选择、设置root密码、网络配置、主机名设置和禁用SELinux的步骤,详细内容请阅读本文,希望能对你有所帮助... ‌AnolisOS‌是由阿里云推出的开源操作系统,旨

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;