Unity Rendering Principle (2) Some easily confused terms

上一篇博客讲了关于渲染流水线中的一些基础知识,其中有一些名词可能有些疑惑,统一总结一下。

What is OpenGL and DirectX?

Both provide graphical programming interfaces, but they are still slightly different. You can take a look at this article.DirectX和OpenGL的对比

The previous content is about the conceptual pipeline and how the GPU implements these pipelines, but in fact, it is a very troublesome thing for developers to directly access the GPU. We may have to deal with various registers and video memory, and image programming. The interface provides a layer of abstraction based on these hardware.

OpenGL and DirectX are the interfaces for programming these image applications. Applications send render commands to these interfaces, which in turn send render commands to the graphics driver, who really knows how to communicate with the GPU. It is the driver who translates the function calls of OpenGL and DX into the language that the GPU can understand. At the same time, they are also responsible for converting data such as textures into formats supported by the GPU.

In a nutshell, our application runs on the CPU. The data required for rendering, such as vertex data, texture data, etc. can be stored in a specific area of the video memory by calling the OpenGL or DirectX graphical interface. Later, developers can issue rendering commands through the image programming interface. These rendering commands are also called Draw Call, which will be translated by the graphics card driver into code that the GPU can understand for real rendering.

Because of the existence of graphics card drivers, almost all GPUs can work with both OpenGL and DirectX. From the perspective of the graphics card, it actually only deals with the graphics card driver. The graphics card driver is equivalent to an intermediary, responsible for dealing with both parties (Graphics Programming Interface and GPU). And in order for their graphics card to work with OpenGL and DirectX at the same time, their graphics card driver must support translation of both.

img

What is HLSL, GLSL, CG?

We talked about many programmable shader stages above, such as vertex shader and slice shader. The programmability of these stages is that we can use a specific language to write programs.

Before the emergence of programmable pipelines, in order to write shader code, developers learned assembly language. In order to open the door for developers, more advanced shading languages have emerged, where advanced is relative to assembly language.

Shading languages are specifically used to write shaders. Common shading languages are DirectX’s HLSL (High Level Shading Language), OpengGL’s GLSL (OpenGL Shading Language), and NVIDIA’s CG (C for Graphics). These languages are translated into Machine-independent assembly language, also known as Intermediate Language (IL), which is handed over to the graphics driver to translate into real machine language, which is the language that the GPU can understand.

The advantage of GLSL is its cross-platform nature. It can work on Windows, Linux, Mac and even mobile platforms. However, this cross-platform nature is due to the fact that OpenGL does not provide a shader compiler, but is driven by the graphics card. The compile of the shader is done. That is, as long as the graphics card driver supports compiling for GLSL, it can run. The advantage of this approach is that since the vendor fully understands their hardware architecture, they know how to get the most out of the hardware. In other words, GLSL is hardware-dependent, not OS-level, but this also means that the compiling result of GLSL depends on the hardware vendor.

For HLSL, the compile of the shader is controlled by Microsoft. Even if different hardware is used, the compile result of the same shader is the same (provided that the version is the same). But the platforms that support HLSL are very limited, almost all of them are Microsoft products, such as Windows, Xbox, etc., because there is no compiler that can compile HLSL on other platforms.

CG is truly cross-platform, and it will be compiled into a corresponding intermediate language according to the different platforms. The cross-platform nature of CG language depends largely on the cooperation with Microsoft, which also makes the syntax of CG language very similar to HLSL. CG language can be seamlessly ported into HLSL code, but the disadvantage is that it cannot play the latest features of OpenGL.

On the Unity platform, we can also choose which language to use. In Unity Shader, we can choose to use “CG/HLSL” or “GLSL”. The quotation marks are because the syntax is just like, not the corresponding shading language in the true sense.

What is Drew?

The meaning of Draw Call itself is very simple, that is, the CPU calls the image programming interface, such as the glDrawElements command of OpenGL or the DrawIndexedPrimitive command of DirectX, to command the GPU to render

How CPU and GPU work in parallel

If there is no pipelining, the CPU needs to wait until the GPU executes the previous rendering task before sending the rendering command again, but this method will obviously cause inefficiency.

The solution is to use a Command Buffer, similar to a message queue.

The command buffer contains a command queue, to which the CPU adds commands, and the GPU retrieves commands.

There are many commands in the command buffer, Draw Call is just one of them, other commands include changing rendering state, etc

https://res.cloudinary.com/dvtfhjxi4/image/upload/v1644838818/origin-of-ray/screenshot-20220214-193925_qiz9ta.png

The CPU adds commands to the buffer through the graphical programming interface, while the GPU reads and executes the commands from it. The white box command is Draw Call, while the command in the red box is used to change the rendering state. The red box is used because this command tends to be more useful.

Why Drew

Before each call to Draw Call, the CPU needs to send a lot of content to the GPU, including data, commands, status, etc. At this stage, the CPU needs to do a lot of things, such as checking the rendering status, etc. Once the CPU has completed these preparations, the GPU can start rendering this time. The rendering ability of the GPU is very strong, and it makes no difference whether it renders 200 or 2000, so the rendering speed often depends on the speed at which the CPU submits commands. If there are too many Draw Calls, the CPU will spend a lot of time submitting Draw Calls, causing the CPU to overload.

How to Reduce Drawing

There are many methods, the most common being batch processing.

Submitting a large number of small Draw Calls is time-consuming, so we merge multiple small Draw Calls into one large one, which is batch processing.

Batch processing requires us to merge meshes in the CPU’s memory, and the merging process is time-consuming. Therefore, batch processing technology is more suitable for static objects, such as earth that does not move. We can also batch moving objects, but each frame needs to be re-merged and sent to the GPU, which has an impact on time and space.

During game development, in order to reduce the overhead of Draw Call, two points need to be noted:

  • Avoid using a large number of small meshes. When use is unavoidable, consider whether it can be merged.

  • Avoid using too many materials. Try to share a material between different meshes.

Does the first optimization plan indicate that each mesh will have a Draw?