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

相关文章

使用WPF实现窗口抖动动画效果

《使用WPF实现窗口抖动动画效果》在用户界面设计中,适当的动画反馈可以提升用户体验,尤其是在错误提示、操作失败等场景下,窗口抖动作为一种常见且直观的视觉反馈方式,常用于提醒用户注意当前状态,本文将详细... 目录前言实现思路概述核心代码实现1、 获取目标窗口2、初始化基础位置值3、创建抖动动画4、动画完成后

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Python实现剪贴板历史管理器

《Python实现剪贴板历史管理器》在日常工作和编程中,剪贴板是我们使用最频繁的功能之一,本文将介绍如何使用Python和PyQt5开发一个功能强大的剪贴板历史管理器,感兴趣的可以了解下... 目录一、概述:为什么需要剪贴板历史管理二、功能特性全解析2.1 核心功能2.2 增强功能三、效果展示3.1 主界面

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

SQL server配置管理器找不到如何打开它

《SQLserver配置管理器找不到如何打开它》最近遇到了SQLserver配置管理器打不开的问题,尝试在开始菜单栏搜SQLServerManager无果,于是将自己找到的方法总结分享给大家,对SQ... 目录方法一:桌面图标进入方法二:运行窗口进入方法三:查找文件路径方法四:检查 SQL Server 安

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Python从零打造高安全密码管理器

《Python从零打造高安全密码管理器》在数字化时代,每人平均需要管理近百个账号密码,本文将带大家深入剖析一个基于Python的高安全性密码管理器实现方案,感兴趣的小伙伴可以参考一下... 目录一、前言:为什么我们需要专属密码管理器二、系统架构设计2.1 安全加密体系2.2 密码强度策略三、核心功能实现详解

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ