参考链接
OpenGL ES编程指南(一):https://cloud.tencent.com/developer/article/2017213
OpenGL ES概要
概述
渲染:把程序提供的几何数据转换成屏幕上的图像的过程叫做渲染,渲染的结果保存在帧缓存中
像素:计算机上显示的图片都是由矩形的颜色点组成,这些颜色点叫做像素,每个像素都是由3个颜色元素组成的,一个红点、一个绿点和一个蓝点、RGB
缓存:OpenGL ES部分运行在CPU上,部分运行在GPU上,协调两个内存区域之间的数据交换,而OpenGL ES为两个内存区域间的数据交换定义了缓存(buffers)的概念,缓存是指图形处理器能够控制和管理的连续RAM。
什么是OpenGL :OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。OpenGL™ 是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。
OpenGL主要功能是什么?
OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL使用简便,效率高。它具有七大功能:
- 1、建模:OpenGL图形库除了提供基本的点、线、多边形的绘制函数外,还提供了复杂的三维物体(球、锥、多面体等)以及复杂曲线和曲面绘制函数。
- 2、变换:OpenGL图形库的变换包括基本变换 和投影变换。基本变换有平移、旋转、缩放、镜像四种变换,投影变换有平行投影(又称正射投影)和透视投 影两种变换。其变换方法有利于减少算法的运行时间,提高三维图形的显示速度。
- 3、颜色模式设置:OpenGL颜色模式有两种,即RGBA模式和颜色索引(Color Index)。
- 4、光照和材质设置:OpenGL光有自发光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light)和高光(Specular Light)。材质是用光反射率来表示。场景(Scene)中物体最终反映到人眼的颜色是光的红绿蓝分量与材质红绿蓝分量的反射率相乘后形成的颜色。
- 5、纹理映射(Texture Mapping)。利用OpenGL纹理映射功能可以十分逼真地表达物体表面细节。
- 6、位图显示和图象增强图象功能除了基本的拷贝和像素读写外,还提供融合(Blending)、抗锯齿(反走样)(Antialiasing)和雾(fog)的特殊图象效果处理。以上三条可使被仿真物更具真实感,增强图形显示的效果。
- 7、双缓存动画(Double Buffering)双缓存即前台缓存和后台缓存,简言之,后台缓存计算场景、生成画面,前台缓存显示后台缓存已画好的画面。
**OpenGL ES是什么?**OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
Open Graphics Library(OpenGL)用于可视化2D和3D数据。 它是一个多用途的开放标准图形库,支持2D和3D数字内容创建, 您可以使用OpenGL来配置3D图形管道并向其提交数据。 顶点被转换并且被点亮,然后组装成图元,并被光栅化用以创建2D图像。 OpenGL旨在将函数调用转换为可发送到底层图形硬件的图形命令。 由于底层硬件专用于处理图形命令,所以OpenGL绘图通常非常快速。
OpenGL for Embedded Systems (OpenGL ES) 是OpenGL的简化版本,它消除了冗余功能,提供了一个易于学习和易于在移动图形硬件中实现的库。OpenGL ES允许应用程序利用底层图形处理器的强大功能。如果您的应用程序的设计要求需要最直接,最全面地访问GPU硬件,则应该使用OpenGL ES。 OpenGL ES的典型客户端包括呈现3D图形的视频游戏和模拟。
OpenGL ES规范定义了一系列独立于平台的API,用于使用GPU硬件渲染图形。实现OpenGL ES的平台提供了:
- 一个渲染上下文用于执行OpenGL ES命令,
- 帧缓冲区用于保存渲染结果,
- 一个或多个渲染目标用以呈现帧缓冲区内容以供显示。
清缓存
在每个帧的开始处,擦除所有帧缓冲区附件的内容,其内容不需要先前的帧来绘制下一帧。 调用glClear函数,将所有缓冲区的位掩码传入以清除
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
对OpenGL ES使用glClear可以放弃渲染缓冲区或纹理的现有内容,从而避免将以前内容加载到内存中的代价高昂的操作。
可视化OpenGL ES
用于可视化OpenGL ES设计的两个方面:作为客户端 - 服务器体系结构和作为管道。 这两种观点都可以用于规划和评估应用程序的体系结构。
OpenGL ES作为客户端 - 服务器体系结构
下图将OpenGL ES形象化为客户端 - 服务器体系结构。 您的应用程序将状态更改,纹理和顶点数据以及渲染命令传递给OpenGL ES客户端。 客户端将这些数据转换为图形硬件可以理解的格式,并将其转发给GPU。 这些进程会增加应用程序图形性能的开销。
实现良好的性能需要仔细管理这些开销。 一个设计良好的应用程序可以减少对OpenGL ES的调用频率,使用适合硬件的数据格式来最大限度地降低翻译成本,并小心管理其本身和OpenGL ES之间的数据流。
OpenGL ES作为图形管道
下图将OpenGL ES形象化为图形管道。
- 应用程序配置图形管道,
- 然后执行绘图命令将顶点数据(vertex)发送到管道,
- 管道的连续阶段运行顶点着色器(shader)来处理顶点数据,将顶点组装成基元(primitives),
- 将基元划分为片段(fragments),
- 运行片段着色器( fragment shader)以计算每个片段的颜色和深度值,并将片段混合到帧缓冲区中以进行显示。
app配置pipeline,然后执行绘图命令将顶点数据向下发送到管线。顶点着色器处理顶点数据,将顶点组装为基元,将图元光栅化为片段(fragments),运行片段着色器计算每个片段的颜色和深度值,并将片段混合到帧缓冲区进行显示
渲染器设计包括编写着色器程序处理管道的顶点和片段阶段,组织输入到这些程序中的顶点和纹理数据以及配置驱动管道的固定阶段的OpenGL ES状态机
图形管道中的各个阶段可以同时计算其结果 - 例如,您的应用程序可能会准备新的基元,而图形硬件的不同部分将对先前提交的几何图形执行顶点和片段计算。 然而,后期阶段取决于早期阶段的产出。 如果任何流水线阶段执行太多工作或执行得太慢,则其他流水线阶段处于闲置状态,直到最慢阶段完成其工作。 根据图形硬件功能,精心设计的应用程序会平衡每个流水线阶段执行的工作。
OpenGL 工作流
OpenGL是一个状态机,它保持自身的状态,除非用户输入一条命令让它改变状态。
颜色、纹理坐标、源因子和目标因子、光源的各种参数,等等,这些都是状态,所以这一句话就包含了上面叙述的所有内容。
此外,“是否启用了光照”、“是否启用了纹理”、“是否启用了混合”、“是否启用了深度测试”等等,这些也都是状态,也符合上面的描述:OpenGL会保持状态,除非我们调用OpenGL函数来改变它。
OpenGL工作流
- Vertex data: 顶点数据。比如我们指定的颜色、纹理坐标、法线向量、顶点坐标等,都属于顶点数据。
- Pixel data: 像素数据。我们在绘制像素、指定纹理时都会用到像素数据。
- Display list: 显示列表。可以把调用的OpenGL函数保存起来
- Evaluators: 求值器。利用求值器可以指定贝赛尔曲线或者贝赛尔曲面,但是实际上还是可以理解为指定顶点、指定纹理坐标、指定法线向量等。
- Per-vertex operations and primitive assembly: 单一的顶点操作以及图元装配。首先对单一的顶点进行操作,比如变换
- Pixel operations: 像素操作。例如把内存中的像素数据格式转化为图形硬件所支持的数据格式。对于纹理,可以替换其中的一部分像素,这也属于像素操作。
- Rasterization: 光栅化。顶点数据和像素数据在这里交汇(可以想像成:顶点和纹理,一起组合成了具有纹理的三角形),形成完整的、可以显示的一整块(可能是点、线段、三角形、四边形,或者其它不规则图形),里面包含若干个像素。这一整块被称为fragment(片段)。
- Per-fragment operations: 片段操作。包括各种片段测试
- Framebuffer: 帧缓冲。这是一块存储空间,显示设备从这里读取数据,然后显示到屏幕。
- Texture assembly: 纹理装配,大概是说纹理的操作和像素操作是相关的吧。
说明:图片中实线表示正常的处理流程,虚线表示数据可以反方向读取,比如可以用glReadPixels从帧缓冲中读取像素数据(实际上是从帧缓冲读取数据,经过像素操作,把显示设备中的像素数据格式转化为内存中的像素数据格式,最终成为内存中的像素数据)
渲染管线
Graphics Pipeline,指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程。
蓝色部分代表的是我们可以注入自定义的着色器的部分。
首先,我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data)。一个顶点(Vertex)是一个3D坐标的数据的集合。而顶点数据是用顶点属性(Vertex Attribute)表示的,简单起见,假定每个顶点只由一个3D位置和一些颜色值组成的吧。
第一个部分是顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标 ,同时顶点着色器允许我们对顶点属性进行一些基本处理。
图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并把所有的点装配成指定图元的形状(比如三角形)。
图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。
几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。片段是OpenGL渲染一个像素所需的所有数据。
片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。
在所有对应颜色值确定以后,最终的对象将会被传到最后一个阶段,我们叫做Alpha测试和混合(Blending)阶段。这个阶段检测片段的对应的深度(和模板(Stencil))值,用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。
GL函数分析
1.glclearcolor
OpenGL的glclearcolor在Mesa中的实现是_mesa_ClearColor
函数。该函数用于指定颜色缓冲区的清除值,用于设置清除颜色。
void GLAPIENTRY
_mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
{
GET_CURRENT_CONTEXT(ctx);
ctx->PopAttribState |= GL_COLOR_BUFFER_BIT;
ctx->Color.ClearColor.f[0] = red;
ctx->Color.ClearColor.f[1] = green;
ctx->Color.ClearColor.f[2] = blue;
ctx->Color.ClearColor.f[3] = alpha;
}
函数接受四个参数:red
、green
、blue
和 alpha
,它们分别表示红、绿、蓝和透明度分量的清除值。
函数首先获取当前的 OpenGL 上下文,然后将 GL_COLOR_BUFFER_BIT
标志设置为上下文的 PopAttribState
成员变量。接下来,将提供的颜色值分别赋值给上下文的 Color.ClearColor.f
数组的对应分量。
union gl_color_union
{
GLfloat f[4];
GLint i[4];
GLuint ui[4];
};
typedef float GLfloat; /* single precision float */
这段代码定义了一个联合体 gl_color_union
,用于存储清除颜色、纹理边界颜色等值。该联合体包含了三个数组成员:f
、i
和 ui
,分别对应浮点数、整数和无符号整数。
f[4]
是一个包含四个GLfloat
类型元素的数组,用于存储浮点数值。这些浮点数值通常不被限制在特定范围内。i[4]
是一个包含四个GLint
类型元素的数组,用于存储整数值。ui[4]
是一个包含四个GLuint
类型元素的数组,用于存储无符号整数值。
2.glClear
glClear
函数的实现代码位于 Mesa 项目的 src/mesa/main/clear.c
文件中。具体实现函数为_mesa_Clear
void GLAPIENTRY
_mesa_Clear(GLbitfield mask)
{
GET_CURRENT_CONTEXT(ctx);
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx, "glClear 0x%x\n", mask);
clear(ctx, mask, false);
}
这段代码实现了 _mesa_Clear
函数,用于执行清除操作。函数接受一个 GLbitfield
类型的参数 mask
,表示需要清除的缓冲区标志位。
首先,通过宏 GET_CURRENT_CONTEXT(ctx)
获取当前的上下文对象 ctx
。
接下来,如果在编译时定义了 MESA_VERBOSE
宏并且设置了 VERBOSE_API
标志位,那么会在调试模式下输出调试信息,使用 _mesa_debug
函数将清除操作的标志位 mask
打印出来。
最后,调用 clear
函数执行实际的清除操作,将上下文对象 ctx
、清除标志位 mask
和一个布尔值 false
作为参数传递给 clear
函数。
该函数的具体实现中 _mesa_debug
函数用于输出调试信息,clear
函数用于执行清除操作。
clear函数的具体实现如下:
这段代码实现了 clear
函数,用于执行实际的清除操作。函数接受一个 struct gl_context
类型的上下文对象指针 ctx
、一个 GLbitfield
类型的参数 mask
表示需要清除的缓冲区标志位,以及一个布尔值 no_error
表示是否禁用错误检查。
static ALWAYS_INLINE void
clear(struct gl_context *ctx, GLbitfield mask, bool no_error)
{
//首先,通过宏 FLUSH_VERTICES(ctx, 0, 0) 刷新顶点,并清空上下文的缓存。
FLUSH_VERTICES(ctx, 0, 0);
/*接下来,如果 no_error 为 false,则进行错误检查。检查 mask 是否包含除了颜色缓冲区、深度缓冲区、模板缓冲区和累积缓冲区之外的标志位,如果有,则调用 _mesa_error 函数生成 GL_INVALID_VALUE 错误并返回。*/
if (!no_error) {
if (mask & ~(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT |
GL_ACCUM_BUFFER_BIT)) {
_mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask);
return;
}
/*然后,根据上下文的 API 类型和功能是否支持,检查是否需要清除累积缓冲区。如果需要清除累积缓冲区但当前上下文的 API 是 OpenGL Core 或者是 OpenGL ES,则生成 GL_INVALID_VALUE 错误并返回。 */
if ((mask & GL_ACCUM_BUFFER_BIT) != 0
&& (ctx->API == API_OPENGL_CORE || _mesa_is_gles(ctx))) {
_mesa_error( ctx, GL_INVALID_VALUE, "glClear(GL_ACCUM_BUFFER_BIT)");
return;
}
}
//如果 ctx->NewState 不为 NULL,则调用 _mesa_update_clear_state 函数更新上下文的清除状态。
if (ctx->NewState) {
_mesa_update_clear_state( ctx ); /* update _Xmin, etc */
}
/*如果需要检查错误,并且当前绘制缓冲区的状态不为 GL_FRAMEBUFFER_COMPLETE_EXT,则生成 GL_INVALID_FRAMEBUFFER_OPERATION_EXT 错误并返回。*/
if (!no_error && ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"glClear(incomplete framebuffer)");
return;
}
//如果启用了光栅化丢弃(Raster Discard),则直接返回。
if (ctx->RasterDiscard)
return;
/*如果当前渲染模式为 GL_RENDER,则根据需要清除的标志位构建要发送给设备驱动的缓冲区掩码(bufferMask)。注意,GL_COLOR_BUFFER_BIT 标志位将根据颜色缓冲区的数量扩展为 BUFFER_BIT_FRONT/BACK_LEFT/RIGHT 或 BUFFER_BIT_COLORn 中的一个或多个。*/
if (ctx->RenderMode == GL_RENDER) {
GLbitfield bufferMask;
/* don't clear depth buffer if depth writing disabled */
if (!ctx->Depth.Mask)
mask &= ~GL_DEPTH_BUFFER_BIT;
bufferMask = 0;
if (mask & GL_COLOR_BUFFER_BIT) {
GLuint i;
for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
gl_buffer_index buf = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
if (buf != BUFFER_NONE && color_buffer_writes_enabled(ctx, i)) {
bufferMask |= 1 << buf;
}
}
}
if ((mask & GL_DEPTH_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.depthBits > 0) {
bufferMask |= BUFFER_BIT_DEPTH;
}
if ((mask & GL_STENCIL_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.stencilBits > 0) {
bufferMask |= BUFFER_BIT_STENCIL;
}
if ((mask & GL_ACCUM_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.accumRedBits > 0) {
bufferMask |= BUFFER_BIT_ACCUM;
}
/*最后,调用 st_Clear 函数执行实际的清除操作,将上下文对象 ctx 和缓冲区掩码 bufferMask 作为参数传递给 st_Clear 函数。st_Clear 函数是一个驱动相关的函数,用于请求驱动清除缓冲区。*/
st_Clear(ctx, bufferMask);
}
}
st_Clear
位于Mesa 项目的 src/mesa/state_tracker/st_cb_clear.c
文件中,调用到pipe->clear
st->pipe->clear(st->pipe, clear_buffers, have_scissor_buffers ? &scissor_state : NULL,
(union pipe_color_union*)&ctx->Color.ClearColor,
ctx->Depth.Clear, ctx->Stencil.Clear);
进入driver层,Panfrost驱动实现的clear函数为panfrost_clear
,在mesa/src/drivers/panfrost/pan_context.c
文件中定义(不同的驱动会分别实现自己的函数)
static void
panfrost_clear(struct pipe_context *pipe, unsigned buffers,
const struct pipe_scissor_state *scissor_state,
const union pipe_color_union *color, double depth,
unsigned stencil)
{
//首先,通过panfrost_render_condition_check函数检查渲染条件是否满足,如果不满足,则直接返回,不执行清除操作。
if (!panfrost_render_condition_check(pan_context(pipe)))
return;
/* Only get batch after checking the render condition, since the check can
* cause the batch to be flushed.
*/
//获取当前的Panfrost上下文ctx和对应的批处理对象batch,这个批处理对象用于提交渲染命令。
struct panfrost_context *ctx = pan_context(pipe);
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
/* At the start of the batch, we can clear for free */
/*检查批处理对象的scoreboard.first_job属性,如果为0(表示批处理对象中没有绘制命令),
则可以直接进行清除操作。调用panfrost_batch_clear函数执行清除操作,并返回。*/
if (!batch->scoreboard.first_job) {
panfrost_batch_clear(batch, buffers, color, depth, stencil);
return;
}
/* Once there is content, clear with a fullscreen quad */
//如果批处理对象中已经有绘制命令存在,则需要使用全屏四边形进行清除操作。
//通过调用panfrost_blitter_save函数保存当前的绘制状态,这个函数用于备份当前的绘制状态以便之后恢复。
panfrost_blitter_save(ctx, false /* render condition */);
//打印性能调试信息,提示正在使用四边形进行清除操作。
perf_debug_ctx(ctx, "Clearing with quad");
/*调用util_blitter_clear函数进行全屏清除。传入清除操作所需的参数,
如帧缓冲的宽度、高度、层数、需要清除的缓冲区、颜色、深度和模板值等。如果帧缓冲的样本数大于1,则设置多重采样标志。*/
util_blitter_clear(
ctx->blitter, ctx->pipe_framebuffer.width, ctx->pipe_framebuffer.height,
util_framebuffer_get_num_layers(&ctx->pipe_framebuffer), buffers, color,
depth, stencil,
util_framebuffer_get_num_samples(&ctx->pipe_framebuffer) > 1);
}
3.glFinish
glFinish
是一个 OpenGL 函数,用于阻塞当前线程,直到所有之前提交的 OpenGL 操作完成。它会等待 GPU 完成所有的渲染操作和命令,并确保它们对后续操作可见。
glFinish
的作用包括:
- 等待所有的绘制命令完成,以确保绘制结果可见。
- 用于性能分析和调试,可以确定绘制命令的执行时间。
- 用于同步 CPU 和 GPU 的操作,确保 CPU 在继续执行之前等待 GPU 完成。
该函数在Mesa中的实现为_mesa_Finish
:
void GLAPIENTRY
_mesa_Finish(void)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
FLUSH_VERTICES(ctx, 0, 0);
st_glFinish(ctx);
}
这段代码实现了OpenGL的glFinish
函数,它的作用是刷新OpenGL命令队列并等待所有命令执行完成。
- 首先,通过宏
GET_CURRENT_CONTEXT(ctx)
获取当前线程的OpenGL上下文,并将其存储在变量ctx
中。 - 接下来,使用宏
ASSERT_OUTSIDE_BEGIN_END(ctx)
进行断言验证,确保当前不处于glBegin
和glEnd
之间的状态。这是因为在这种状态下调用glFinish
可能会导致错误。 - 然后,通过宏
FLUSH_VERTICES(ctx, 0, 0)
刷新尚未处理的顶点数据。这将提交上下文ctx
中的顶点数据,以便OpenGL进行处理。 - 最后,调用
st_glFinish(ctx)
函数,它是驱动程序特定的函数,用于等待命令的完成。该函数将等待所有已提交的命令执行完成,并确保操作完成后再继续执行下一步。
通过调用glFinish
,可以确保在继续执行代码之前,所有之前提交的OpenGL命令都已经完成,从而实现同步。
void
st_glFinish(struct gl_context *ctx)
{
struct st_context *st = st_context(ctx);
st_finish(st);
st_manager_flush_frontbuffer(st);
}
这段代码是 Mesa 中针对 Mesa/OpenGL-to-Gallium3D(简称为Gallium3D)的驱动实现的 st_glFinish
函数。
该函数首先将 struct gl_context
类型的上下文转换为 struct st_context
类型的上下文,这是用于 Mesa 到 Gallium3D 的适配层。这是因为 Gallium3D 是一个跨平台的图形驱动架构,Mesa 将 OpenGL API 转换为 Gallium3D API,并通过适配层与底层驱动程序进行交互。
接下来,函数调用 st_finish(st)
,其中 st_finish
是 Gallium3D 驱动程序提供的函数,用于等待命令的完成。它会等待所有之前提交的命令执行完成,并确保操作完成后再继续执行。
最后,函数调用 st_manager_flush_frontbuffer(st)
,这个函数用于将前端缓冲区的内容刷新到显示设备上。它将前端缓冲区的渲染结果传输到屏幕上,以便用户能够看到渲染的结果。
综上所述,st_glFinish
函数在 Gallium3D 驱动层面上完成了等待命令完成和刷新前端缓冲区的操作。这是为了确保在继续执行代码之前,所有之前提交的OpenGL命令都已经执行完成,并将最终的渲染结果显示到屏幕上。
捕获和回放OPenGL命令流
要使用 apitrace
工具捕获和回放 OpenGL 命令流,可以按照以下步骤进行操作:
-
安装
apitrace
工具:首先,你需要在你的系统上安装apitrace
工具。可以从官网(https://github.com/apitrace/apitrace)下载并按照其提供的安装说明进行安装。 -
捕获 OpenGL 命令流:使用
apitrace trace
命令来捕获应用程序的 OpenGL 命令流。例如,要捕获名为your_application
的应用程序的命令流,可以执行以下命令:apitrace trace your_application
这将启动应用程序,并将捕获的命令流保存为
.trace
文件。
-
回放 OpenGL 命令流:使用
apitrace replay
命令来回放捕获的命令流并查看图形输出。例如,要回放名为your_trace.trace
的命令流,可以执行以下命令:apitrace replay your_trace.trace
这将回放命令流并显示应用程序的图形输出窗口。
-
查看跟踪
apitrace dump application.trace
将应用程序的命令流转储为可读的文本文件,转储的命令流将以较为详细的形式显示应用程序的命令、状态和数据。
-
启动GUI
qapitrace application.trace
按ctrl+t
可以查看每帧的缩略图
查看状态参数以及surface