全球图形学领域教育的领先者、自研引擎的倡导者、底层技术研究领域的技术公开者,东汉书院在致力于使得更多人群具备内核级竞争力的道路上,将带给小伙伴们更多的公开技术教学和视频,感谢一路以来有你的支持。我们正在用实际行动来帮助小伙伴们构建一套成体系的图形学知识架构,你在我们这里获得的不止于那些毫无意义的代码,我们这里更多的是代码背后的故事,以及精准、透彻的理解。我们不会扔给人们一本书或者给个思路让人们去自学,我们是亲自来设计出好的资源,让人们明白到底背后还有哪些细节。
这里插播一个引擎大赛的消息,感兴趣的同学可以看一眼,这也是东汉书院的立项使命:
疯狂的程序员:自研引擎大赛zhuanlan.zhihu.com大赛官方主页
东汉书院-自己动手写游戏引擎edu.battlefire.cn参赛作品列表
疯狂的程序员:参赛作品1-NaturalEnginezhuanlan.zhihu.com疯狂的程序员:参赛作品2-Colble离线室内渲染器和Juziimo实时外观渲染器zhuanlan.zhihu.comChapter 12. Controlling and Monitoring the Pipeline
What You’ll Learn in This Chapter
- How to ask OpenGL about the progress of your commands down the graphics pipeline.
- How to measure the time taken for your commands to execute.
- How to synchronize your application with OpenGL and how to synchronize multiple OpenGL contexts with each other.
你将会在本章学到啥
- 如何询问OpenGL你的指令在图形管线中的执行进度
- 如何计算出你的指令花费了多少时间
- 如何处理OpenGL与你的程序的同步问题以及如何同步多个OpenGL的渲染上下文
This chapter is about the OpenGL pipeline and how it executes your commands. As your application makes OpenGL function calls, work is placed in the OpenGL pipeline and makes its way down it one stage at a time. This takes time, and you can measure that span. This allows you to tune your application’s complexity to match the performance of the graphics system and to measure and control latency, which is important for real-time applications. In this chapter, you’ll also learn how to synchronize your application’s execution to that of OpenGL commands you’ve issued and even how to synchronize multiple OpenGL contexts with each other.
本章是介绍OpenGL的管线的以及它如何执行你的指令。当你的程序调用OpenGL的API的时候,这些指令都会在OpenGL的管线里得到执行并且每次执行一个阶段。这个操作是耗费时间的,你可以计算出花费了多少时间。 这可以让你去测试你程序的复杂度然后去很好适配你的图形系统的性能,并且掌握并处理好延迟,这对于实时应用程序来说是非常重要的。在本章中,你将同样会学到如何去同步你程序发送给OpenGL的那些指令甚至能学到 如何去同步多个OpenGL的渲染上下文。
Queries
Queries are a mechanism to ask OpenGL what’s happening in the graphics pipeline. There’s plenty of information that OpenGL can tell you; you just need to know what to ask—and how to ask the question.
Queries是一种查询OpenGL图形管线里正在发生什么的一种机制。你可以查询到很多东西,你需要做的就是知道可以查询什么以及如何去查询。
Remember your early days in school? The teacher wanted you to raise your hand before asking a question. This was almost like reserving your place in line for asking the question—the teacher didn’t know yet what your question was going to be, but she knew that you had something to ask. OpenGL is similar. Before we can ask a question, we have to reserve a spot so that OpenGL knows the question is coming. Questions in OpenGL are represented by query objects, and much like any other object in OpenGL, query objects must be reserved, or generated. To do this, call glGenQueries(), passing it the number of queries you want to reserve and the address of a variable (or array) where you would like the names of the query objects to be placed:
回想起在学校里的那些日子会想到啥?老师们会希望你在提问之前先举手。你这么做就非常类似于在一个队列里面占据一个问问题的位置,这时候老师还不知道你想问什么,但是他们知道你有东西要问。OpenGL是类似的。 在你问问题之前,你必须让我们知道你想要问问题。OpenGL里面使用query object来表现问题的,就跟OpenGL里面的其他object一样,query object必须实现申明然后生成。我们可以调用glGenQueries,传入你希望 预留多少个query object以及传入一个地址,告诉OpenGL你希望那些query object名字被写进哪里:
void glGenQueries(GLsizei n,GLuint *ids);
The function reserves some query objects for you and gives you their names so that you can refer to them later. You can generate as many query objects you need in one go:
这个函数预留了一些query object并且给出了他们的名字,你可以在后面的代码中使用这些名字来引用这些query object。你可以一次性生成很多个query object:
GLuint one_query;
GLuint ten_queries[10];
glGenQueries(1, &one_query);
glGenQueries(10, ten_queries);
In this example, the first call to glGenQueries() generates a single query object and returns its name in the variable one_query. The second call to glGenQueries() generates ten query objects and returns ten names in the array ten_queries. In total, 11 query objects have been created, and OpenGL has reserved 11 unique names to represent them. It is very unlikely, but still possible, that OpenGL will not be able to create a query for you; in this case it returns 0 as the name of the query. A well-written application always checks that glGenQueries() returns a non-zero value for the name of each requested query object. If there is a failure, OpenGL keeps track of the reason, and you can find that out by calling glGetError().
在本例子中,第一个对glGenQueries的调用中生成了一个query object并且把它的名字写入了one_query这个变量里面。第二次对glGenQueries的调用生成了10个query object并且把10个名字写入了ten_queries 变量里面。你总共生成了11个query object,OpenGL为你预留了11个独一无二的名字来表示这些query object。当name里面的值是0的时候,就表示OpenGL不能给你创建query object。一个良好的编程习惯就是 在调用了glGenQueries之后,去检查一下返回值是不是非0。如果这个操作失败了,OpenGL会保留一份错误原因,你可以通过glGetError()来获取到为什么失败了。
Each query object reserves a small but measurable amount of resources from OpenGL. These resources must be returned to OpenGL because, if they are not, OpenGL may run out of space for queries and fail to generate more for the application later. To return the resources to OpenGL, call glDeleteQueries():
每一个query object会从OpenGL里面占有一份小的,但是可以度量的资源。这些资源必须最后回收给OpenGL,因为如果它们没有被回收的话,那么OpenGL可能会没有内存了并且无法为应用程序创建更多的queries。 我们可以调用glDeleteQueries来把query object的资源回收给OpenGL。
void glDeleteQueries(GLsizei n,const GLuint *ids);
This works similarly to glGenQueries()—it takes the number of query objects to delete and the address of a variable or array holding their names:
这个跟glGenQueries类似,它会接受两个参数,第一个是你想回收多少query object,第二个参数就是具体的这些你想回收的query object的存放位置。
glDeleteQueries(10, ten_queries);
glDeleteQueries(1, &one_query);
After the queries are deleted, they are essentially gone for good. The names of the queries can’t be used again unless they are given back to you by another call to glGenQueries().
当你的queries被删除了之后,他们基本上都是没问题的,这些名字是不会被重用的,直到你下次调用glGenQueries的时候再次获得它们。
我们核心关注和讨论的领域是引擎的底层技术以及商业化方面的信息,可能并不适合初级入门的同学。另外官方维护两个公众号,第一个公众号是关于我们企业自身产品的信息与动态的公众号,如果对我们自身信息与动态感兴趣的同学,可以关注图形之心。
除此之外,我们为了更频繁的发布一些咨询与文章,我们维护的第二个公众号是“内核观察”,内核观察提供的主要是一些与我们无关的咨询与文章。
只言片语,无法描绘出整套图形学领域的方方面面,只有成体系的知识结构,才能够充分理解和掌握一门科学,这是艺术。我们已经为你准备好各式各样的内容了,东汉书院,等你来玩。