OpenGL 概念整理
OpenGL 概念整理
1. OpenGL
1.1 术语说明
概念 | 描述 | 版本 |
---|---|---|
OpenGL | Open Graphics Library Khronos 定义GPU功能实现的SPEC,标准API | 4.6 |
OpenGL ES | Embedded System 为嵌入式系统定义的相关补充接口 | 3.2 |
EGL | 用于GPU渲染与机器原生窗口之间通信的API,独立于OpenGL ES各个版本 | |
Vulkan | Khronos组织新定义的接口,相比于OpenGL更加高效 | 1.2 |
1.2 OpenGL 理解
从功能上理解,OpenGL 是开发者操作GPU渲染的工具,需要将所定义的行为给到GPU去执行渲染操作:
- 将绘制源数据提供给到GPU;
- 将执行操作(程序)给到GPU;
- 绘制完成后将显示内容提供给到framebuffer;
针对于上述功能需求,Khronos将OpenGL设计成为一组状态机,规定一系列的变量描述OpenGL此刻应当如何运行,其状态通常被称为上下文(Context),我们可以在程序中配置他们,这些状态会一直生效到下次改变:
- Context:作为状态机的上下文,描述当前状态的值以及改变状态的值;
- Object: OpenGL将一系列具有相同功能的状态抽象出状态的子集称之为对象
- OpenGL Shading Language:GPU的编程语言,使用GLSL来编写shader程序
概念 | 说明 |
---|---|
Vertex | 顶点 GPU渲染绘制是对于点的操作,这里是物体顶点坐标的计算操作 |
Fragment | 片元操作,理解为对于像素点的颜色计算操作 |
Shader | 着色器:GPU中执行程序的名称(ARM 将HW 叫做Shader Core),一般有Vertex、fragment、geometry等 |
Texture | 作为Fragment输入操作的源数据,多种方式提供给到GPU |
1.3 VBO、EBO、VAO的理解
顶点数据如何提供给到GPU:
对象 | 说明 |
---|---|
VBO | Vertex Buffer Object,一块buffer,描述顶点的数据对象 |
EBO | Element Buffer Object,描述元素的数据对象,存储顶点的索引,可以复用顶点构建三角形 |
VAO | Vertex Arrary Object,一块buffer,顶点数组对象,可以描述多个顶点 |
GLfloat vertices[] = {0.5f, 0.5f, 0.0f, // 右上角0.5f, -0.5f, 0.0f, // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f // 左上角
};GLuint indices[] = { // 注意索引从0开始! 0, 1, 3, // 第一个三角形1, 2, 3 // 第二个三角形
};GLuint VBO, VAO, EBO;//声明变量glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO); //生成对应bufferglBindVertexArray(VAO); //绑定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO 将我们定义的顶点数据填充到VBO中glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);绑定EBO 并填充数据glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);//设置顶点属性指针,这里是描述VAO中各个数据的含义glEnableVertexAttribArray(0); //解除绑定glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);
上述code建立了VAO的数据索引,是初始化过程,后续在实际绘制时绑定VAO即可使用上述数据;
1.4 Shader
Shader是运行在GPU上的程序,这些程序是Pipeline中某一个特定的环节执行(所谓vertex、fragment、geometry shader的可编程特性就是这里实现的)
Shader只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
Shader 程序使用类C语言实现,即上文提到的GLSL;
典型Shader程序基本机构如下:
#version version_number //声明版本号,特性不同in type in_variable_name;//声明输入变量
in type in_variable_name;out type out_variable_name;//声明输出变量uniform type uniform_name;// 声明uniform变量int main()//主程序
{// 处理输入并进行一些图形操作...// 输出处理过的结果到输出变量out_variable_name = weird_stuff_we_processed;
}
Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
1.5 标准化设备坐标
OpenGL 中的坐标如下图所示:
X轴和Y轴都是从(-1, 1)范围,对应到实际屏幕上
2. OpenGL ES 介绍
OpenGL ES 是 OpenGL API的子集,针对嵌入式设备设计;
OpenGL ES 是从 OpenGL 裁剪的定制而来的,去除了glBegin/glEnd,四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元等许多非绝对必要的特性;
3. EGL 介绍
EGL 是 渲染API 和原生窗口系统之间的接口;
- 可以理解为GPU渲染完成后需要将out数据丢到framebuffer或者其他buffer中用于后续显示操作,所以这部分与平台特性强相关,所以抽象出来一组标准接口,作为GPU渲染与Display显示的桥梁;
提供如下机制:
- 与设备原生窗口通信
- 查询绘制surface的可用类型和配置
- 创建绘制surface
- 同步渲染
- 管理纹理贴图等渲染资源
主要接口如下:
检查错误:EGL API 成功返回EGL_TRUE,失败返回EGL_FALSE,具体原因需要调用如下接口
EGLint eglGetError();
创建本地系统和OpenGL ES的连接并进行初始化
//创建display EGLDisplay eglDisplay(EGLNativeDisplayType displayId); //初始化 EGLBoolean eglInitialize(EGLDisplay display, // 创建步骤时返回的对象EGLint *majorVersion, // 返回 EGL 主版本号EGLint *minorVersion); // 返回 EGL 次版本号
找到可用surface配置项
//获取所有配置 EGLBoolean eglGetConfigs(EGLDisplay display, // 指定显示的连接EGLConfig *configs, // 指定 GLConfig 列表EGLint maxReturnConfigs, // 最多返回的 GLConfig 数EGLint *numConfigs); // 实际返回的 GLConfig 数 //查询EGL Config配置 EGLBoolean eglGetConfigAttrib(EGLDisplay display, // 指定显示的连接EGLConfig config, // 指定要查询的 GLConfigEGLint attribute, // 返回特定属性EGLint *value); // 返回值 // 确认配置 EGLBoolean eglChooseChofig(EGLDispay display, // 指定显示的连接const EGLint *attribList, // 指定 configs 匹配的属性列表,可以为 NULLEGLConfig *config, // 调用成功,返会符合条件的 EGLConfig 列表EGLint maxReturnConfigs, // 最多返回的符合条件的 GLConfig 数ELGint *numConfigs ); // 实际返回的符合条件的 EGLConfig 数
创建Surface
EGLSurface eglCreateWindowSurface(EGLDisplay display, // 指定显示的连接EGLConfig config, // 符合条件的 EGLConfigEGLNatvieWindowType window, // 指定原生窗口const EGLint *attribList); // 指定窗口属性列表,可为 NULL
创建并关联上下文
//创建上下文 EGLContext eglCreateContext(EGLDisplay display, // 指定显示的连接EGLConfig config, // 前面选好的 EGLConfigEGLContext shareContext, // 允许其它 EGLContext 共享数据,使用 EGL_NO_CONTEXT 表示不共享const EGLint* attribList); // 指定操作的属性列表,只能接受一个属性 EGL_CONTEXT_CLIENT_VERSION //关联上下文 EGLBoolean eglMakeCurrent(EGLDisplay display, // 指定显示的连接EGLSurface draw, // EGL 绘图表面EGLSurface read, // EGL 读取表面EGLContext context); // 指定连接到该表面的上下文
如下为完整流程举例说明:
ret = modeset_open(&fd, "/dev/dri/card0");
//...
ret = modeset_prepare(fd);
//...
gbm = gbm_create_device(fd);
//...
gbm_surface = gbm_surface_create(gbm, pws_current->ws_width, pws_current->ws_height, GBM_FORMAT_ARGB8888, 0);
//...
egl_display = eglGetDisplay(gbm);
//...
ret = eglInitialize(egl_display, NULL, NULL);
//...
ret = eglGetConfigs(egl_display, NULL, 0, &max_config_num);
//...
pconfigs = (EGLConfig*)malloc(sizeof(EGLConfig) * max_config_num);
//...
ret = eglChooseConfig(egl_display, attr, pconfigs, max_config_num, &max_config_num);
//...
int i=0;
for ( i=0; i<max_config_num; i++ )
{EGLint value;/*Use this to explicitly check that the EGL config has the expected color depths */eglGetConfigAttrib( egl_display, pconfigs[i], EGL_RED_SIZE, &value );if ( 8 != value ) continue;eglGetConfigAttrib( egl_display, pconfigs[i], EGL_GREEN_SIZE, &value );if ( 8 != value ) continue;eglGetConfigAttrib( egl_display, pconfigs[i], EGL_BLUE_SIZE, &value );if ( 8 != value ) continue;eglGetConfigAttrib( egl_display, pconfigs[i], EGL_ALPHA_SIZE, &value );if ( 8 != value ) continue;eglGetConfigAttrib( egl_display, pconfigs[i], EGL_SAMPLES, &value );if ( 4 != value ) continue;printf("-------use config[%d] ------\r\n", i);ecfg = pconfigs[i];break;
}egl_surface = eglCreateWindowSurface(egl_display, ecfg, (NativeWindowType)gbm_surface, NULL);
//...
egl_context = eglCreateContext(egl_display, ecfg, EGL_NO_CONTEXT, ctxattr);
//...
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
上述为标准的EGL获取display的path,其目的是获取到显示device和申请到surface用于后续buffer调换;
4. buffer流转图示
单buffer:
如上图,只申请一个buffer进行流转的情况,由于只有一个buffer,所以存在Display模块正在显示的时候GPU同时绘制,则出现撕裂;
双buffer:
双buffer缓冲机制即添加同步操作,避免不同的user操作同一个buffer的行为:
- GPU在swapbuffer操作时对当前idle状态buffer进行渲染操作;
- 渲染完成后调用page flip操作将render完成的buffer地址给到Display模块;
- Display模块会在下次vsync信号过来,显示该buffer数据;
双buffer可以有效的避免buffer绘制时显示异常的问题(比如撕裂),但是由于render和display操作耗时不同,会存在等待耗时较长的操作的情况(一般是等待render);
多buffer流转:
多buffer流转可以解决上述等待的情况,可以理解为将render和show操作分离,或者将render时间与show时间的差值划分到各个buffer中;
注意一定做好同步操作,否则会出现撕裂抖帧等问题、
- GPU 从Idle queue中获取到buffer进行渲染操作,完成后将其添加到busy queue中;
- Display模块从Busy queue中获取到buffer进行显示操作,在下次Vsync过来时替换buffer显示,如果此时Busy queue中为空,则仍显示此帧数据,并且不释放这个buffer;
- 如果GPU申请Idle buffer时为空,则等待show完成,一般来说合理的buffer数量为3~5个,也可以动态申请,即在没有buffer时动态申请添加;
OpenGL 概念整理相关推荐
- AIFramework基本概念整理
AIFramework基本概念整理 本文介绍: • 对天元 MegEngine 框架中的 Tensor, Operator, GradManager 等基本概念有一定的了解: • 对深度学习中的前向传 ...
- 特征值 奇异值分解 概念整理
特征值分解.奇异值分解.PCA概念整理 标签: PCA特征值及向量奇异值QR算法 2014-01-18 14:21 16402人阅读 评论(5) 收藏 举报 本文章已收录于: 分类: 机器学习(9) ...
- 区块链中的基本概念整理
区块链中的基本概念整理 区块链本身是由多种技术集合而成,涉及了多方面的内容,而在其组合应用的过程中,同时也产生了很多新的概念.对于这些概念的整理和理解,有助于更加深刻的理解区块链的本质,也可以指导我们 ...
- 电分、模电、数电总复习之爱课堂题目概念整理
本文模电数电部分转载自博客园_模电数电爱课堂概念题整理 模电.数电总复习之爱课堂题目概念整理 电分总复习之爱课堂题目概念整理(原创)(不定期更新) 模电总复习之爱课堂题目概念整理 Chapter 1 ...
- SR领域概念整理个人笔记
概念整理(持更) 1. CV注意力机制 https://jishuin.proginn.com/p/763bfbd3296c 空间注意力模块:特征图每个位置进行attention调整,二维调整 通道注 ...
- 【jeecg-boot项目开发crm】:平台技术点——day05【Java定时任务解决方案:九、触发器,调度器概念整理】:图灵课堂
九.触发器,调度器概念整理 1 触发器的优先级 1. 1判断错过触发的条件和产生的原因 1.2错过触发之后要怎么处理呢[下面给出策略] 默认使用的策略: SimpleTrigger[常用]: new* ...
- 交叉熵(cross entropy)概念整理
网上写得实在是太乱,整理下: 交叉熵函数: H(p,q)=Ep[−logq]=−∑x∈χp(x)logq(x)①H(p,q)=E_p[-log\ q]=-\sum_{x\in \chi}p(x)log ...
- IIS Web 服务器/ASP.NET 运行原理基本知识概念整理
前言: 记录 IIS 相关的笔记还是从公司笔试考核题开始的,问 Application Pool 与 AppDomain 的区别? 促使我对进程池进了知识的学习,所以记录一下学习的笔记. 我们知道现在 ...
- 数据库基本概念整理及常用SQL语句
数据库也是计算机类笔试面试中不可避免会遇到的考点,尤其是银行和部分传统软件类公司.这里根据整理的资料,对数据库的相关知识也做个总结吧.希望学过数据库但长时间不用的同学根据这些知识能够回忆和重拾,没学过 ...
- 深度神经网络概念整理,最简单的神经网络是什么样子?
目录 1.神经网络训练过程 2.基础概念 3.数据预处理手段 4.数据处理库 5.训练集.测试集,测试集 5.损失函数 6.优化器 7.激活函数 8.hello world 9.总结 深度神经网络就是 ...
最新文章
- air什么意思中文_Air译中文是什么意思,the air中文是什么意思
- 13、设置默认字符集和校对规则
- android x86一键安装,安卓
- Easyui主要组件用法
- [Abp 源码分析]后台作业与后台工作者
- [转帖]USB-C和Thunderbolt 3连接线你搞懂了吗?---没搞明白.
- SpringBoot如何使用拦截器
- leetcode 130 python
- 还在用Postman?来,花2分钟体验下ApiPost的魅力!
- python 缺省参数_week04_python函数缺省值
- springboot配置手动提交_kafka教程-springboot消费者-手动提交offset
- 用OpenCV制作一个低成本的立体相机
- 中州韵输入法 linux 小鹤双拼,App Store 上的“iRime输入法-小鹤双拼五笔郑码输入法”...
- c语言科学计数法输出1_e10,PAT 1024科学计数法的代码实现及错误分析(C语言)
- 在线学习PS设计精讲精练记录(5)
- 大童保险确认获得投资:德弘资本等出资15亿元,获得约33%股权
- 地铁AFC付出体式格局近况及移动付出安好性探究
- 《Linux命令行与shell脚本大全》笔记
- FPGA数字信号处理(四)Quartus FIR IP核实现
- 通过Fiddler Script替换请求/响应内容
热门文章
- 配置nginx作为下载站点
- UVA - 10129 Play on Words(欧拉回路)
- MVC中验证码的生成
- 32获取外部中断状态_STM8单片机中断的主要功能解析
- 581. Shortest Unsorted Continuous Subarray
- sql 判断连续数字
- 小红书创始人瞿芳回应裁员风波:战略部署清晰 人员翻倍
- Hadoop组件启动的三种方式及配置SSH无密码登入
- 使用synchronized(非this对象)同步代码块解决脏读问题
- URL对象中前而几个方法都非常容易理解,而该对象提供的openStream()可以读取该 URL资源...