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去执行渲染操作:

  1. 将绘制源数据提供给到GPU;
  2. 将执行操作(程序)给到GPU;
  3. 绘制完成后将显示内容提供给到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
  • 同步渲染
  • 管理纹理贴图等渲染资源

主要接口如下:

  1. 检查错误:EGL API 成功返回EGL_TRUE,失败返回EGL_FALSE,具体原因需要调用如下接口

    EGLint eglGetError();
    
  2. 创建本地系统和OpenGL ES的连接并进行初始化

    //创建display
    EGLDisplay eglDisplay(EGLNativeDisplayType displayId);
    //初始化
    EGLBoolean eglInitialize(EGLDisplay display, // 创建步骤时返回的对象EGLint *majorVersion, // 返回 EGL 主版本号EGLint *minorVersion); // 返回 EGL 次版本号
    
  3. 找到可用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 数
    
  4. 创建Surface

    EGLSurface eglCreateWindowSurface(EGLDisplay display, // 指定显示的连接EGLConfig config, // 符合条件的 EGLConfigEGLNatvieWindowType window, // 指定原生窗口const EGLint *attribList); // 指定窗口属性列表,可为 NULL
    
  5. 创建并关联上下文

    //创建上下文
    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 概念整理相关推荐

  1. AIFramework基本概念整理

    AIFramework基本概念整理 本文介绍: • 对天元 MegEngine 框架中的 Tensor, Operator, GradManager 等基本概念有一定的了解: • 对深度学习中的前向传 ...

  2. 特征值 奇异值分解 概念整理

    特征值分解.奇异值分解.PCA概念整理 标签: PCA特征值及向量奇异值QR算法 2014-01-18 14:21 16402人阅读 评论(5) 收藏 举报 本文章已收录于: 分类: 机器学习(9) ...

  3. 区块链中的基本概念整理

    区块链中的基本概念整理 区块链本身是由多种技术集合而成,涉及了多方面的内容,而在其组合应用的过程中,同时也产生了很多新的概念.对于这些概念的整理和理解,有助于更加深刻的理解区块链的本质,也可以指导我们 ...

  4. 电分、模电、数电总复习之爱课堂题目概念整理

    本文模电数电部分转载自博客园_模电数电爱课堂概念题整理 模电.数电总复习之爱课堂题目概念整理 电分总复习之爱课堂题目概念整理(原创)(不定期更新) 模电总复习之爱课堂题目概念整理 Chapter 1 ...

  5. SR领域概念整理个人笔记

    概念整理(持更) 1. CV注意力机制 https://jishuin.proginn.com/p/763bfbd3296c 空间注意力模块:特征图每个位置进行attention调整,二维调整 通道注 ...

  6. 【jeecg-boot项目开发crm】:平台技术点——day05【Java定时任务解决方案:九、触发器,调度器概念整理】:图灵课堂

    九.触发器,调度器概念整理 1 触发器的优先级 1. 1判断错过触发的条件和产生的原因 1.2错过触发之后要怎么处理呢[下面给出策略] 默认使用的策略: SimpleTrigger[常用]: new* ...

  7. 交叉熵(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 ...

  8. IIS Web 服务器/ASP.NET 运行原理基本知识概念整理

    前言: 记录 IIS 相关的笔记还是从公司笔试考核题开始的,问 Application Pool 与 AppDomain 的区别? 促使我对进程池进了知识的学习,所以记录一下学习的笔记. 我们知道现在 ...

  9. 数据库基本概念整理及常用SQL语句

    数据库也是计算机类笔试面试中不可避免会遇到的考点,尤其是银行和部分传统软件类公司.这里根据整理的资料,对数据库的相关知识也做个总结吧.希望学过数据库但长时间不用的同学根据这些知识能够回忆和重拾,没学过 ...

  10. 深度神经网络概念整理,最简单的神经网络是什么样子?

    目录 1.神经网络训练过程 2.基础概念 3.数据预处理手段 4.数据处理库 5.训练集.测试集,测试集 5.损失函数 6.优化器 7.激活函数 8.hello world 9.总结 深度神经网络就是 ...

最新文章

  1. air什么意思中文_Air译中文是什么意思,the air中文是什么意思
  2. 13、设置默认字符集和校对规则
  3. android x86一键安装,安卓
  4. Easyui主要组件用法
  5. [Abp 源码分析]后台作业与后台工作者
  6. [转帖]USB-C和Thunderbolt 3连接线你搞懂了吗?---没搞明白.
  7. SpringBoot如何使用拦截器
  8. leetcode 130 python
  9. 还在用Postman?来,花2分钟体验下ApiPost的魅力!
  10. python 缺省参数_week04_python函数缺省值
  11. springboot配置手动提交_kafka教程-springboot消费者-手动提交offset
  12. 用OpenCV制作一个低成本的立体相机
  13. 中州韵输入法 linux 小鹤双拼,‎App Store 上的“iRime输入法-小鹤双拼五笔郑码输入法”...
  14. c语言科学计数法输出1_e10,PAT 1024科学计数法的代码实现及错误分析(C语言)
  15. 在线学习PS设计精讲精练记录(5)
  16. 大童保险确认获得投资:德弘资本等出资15亿元,获得约33%股权
  17. 地铁AFC付出体式格局近况及移动付出安好性探究
  18. 《Linux命令行与shell脚本大全》笔记
  19. FPGA数字信号处理(四)Quartus FIR IP核实现
  20. 通过Fiddler Script替换请求/响应内容

热门文章

  1. 配置nginx作为下载站点
  2. UVA - 10129 Play on Words(欧拉回路)
  3. MVC中验证码的生成
  4. 32获取外部中断状态_STM8单片机中断的主要功能解析
  5. 581. Shortest Unsorted Continuous Subarray
  6. sql 判断连续数字
  7. 小红书创始人瞿芳回应裁员风波:战略部署清晰 人员翻倍
  8. Hadoop组件启动的三种方式及配置SSH无密码登入
  9. 使用synchronized(非this对象)同步代码块解决脏读问题
  10. URL对象中前而几个方法都非常容易理解,而该对象提供的openStream()可以读取该 URL资源...