10000 Add Chinese Translation framework · chirsz-ever/VulkanTutorial@6802acb · GitHub
[go: up one dir, main page]

Skip to content

Commit 6802acb

Browse files
committed
Add Chinese Translation framework
1 parent ed67ed2 commit 6802acb

36 files changed

+10949
-1
lines changed

config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"files": ["README.md", "build_ebook.py","daux.patch",".gitignore"],
3434
"folders": ["ebook"]
3535
},
36-
"languages": {"en": "English", "fr": "Français"},
36+
"languages": {"en": "English", "fr": "Français", "zh": "中文"},
3737
"language": "en",
3838
"processor": "VulkanLinkProcessor"
3939
}

zh/00_Introduction.md

Lines changed: 269 additions & 0 deletions
Large diffs are not rendered by default.

zh/01_Overview.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
---
2+
title: 内容概览
3+
---
4+
5+
This chapter will start off with an introduction of Vulkan and the problems
6+
it addresses. After that we're going to look at the ingredients that are
7+
required for the first triangle. This will give you a big picture to place each
8+
of the subsequent chapters in. We will conclude by covering the structure of the
9+
Vulkan API and the general usage patterns.
10+
11+
## Origin of Vulkan
12+
13+
Just like the previous graphics APIs, Vulkan is designed as a cross-platform
14+
abstraction over [GPUs](https://en.wikipedia.org/wiki/Graphics_processing_unit).
15+
The problem with most of these APIs is that the era in which they were designed
16+
featured graphics hardware that was mostly limited to configurable fixed
17+
functionality. Programmers had to provide the vertex data in a standard format
18+
and were at the mercy of the GPU manufacturers with regards to lighting and
19+
shading options.
20+
21+
As graphics card architectures matured, they started offering more and more
22+
programmable functionality. All this new functionality had to be integrated with
23+
the existing APIs somehow. This resulted in less than ideal abstractions and a
24+
lot of guesswork on the graphics driver side to map the programmer's intent to
25+
the modern graphics architectures. That's why there are so many driver updates
26+
for improving the performance in games, sometimes by significant margins.
27+
Because of the complexity of these drivers, application developers also need to
28+
deal with inconsistencies between vendors, like the syntax that is accepted for
29+
[shaders](https://en.wikipedia.org/wiki/Shader). Aside from these new features,
30+
the past decade also saw an influx of mobile devices with powerful graphics
31+
hardware. These mobile GPUs have different architectures based on their energy
32+
and space requirements. One such example is [tiled rendering](https://en.wikipedia.org/wiki/Tiled_rendering),
33+
which would benefit from improved performance by offering the programmer more
34+
control over this functionality. Another limitation originating from the age of
35+
these APIs is limited multi-threading support, which can result in a bottleneck
36+
on the CPU side.
37+
38+
Vulkan solves these problems by being designed from scratch for modern graphics
39+
architectures. It reduces driver overhead by allowing programmers to clearly
40+
specify their intent using a more verbose API, and allows multiple threads to
41+
create and submit commands in parallel. It reduces inconsistencies in shader
42+
compilation by switching to a standardized byte code format with a single
43+
compiler. Lastly, it acknowledges the general purpose processing capabilities of
44+
modern graphics cards by unifying the graphics and compute functionality into a
45+
single API.
46+
47+
## What it takes to draw a triangle
48+
49+
We'll now look at an overview of all the steps it takes to render a triangle in
50+
a well-behaved Vulkan program. All of the concepts introduced here will be
51+
elaborated on in the next chapters. This is just to give you a big picture to
52+
relate all of the individual components to.
53+
54+
### Step 1 - Instance and physical device selection
55+
56+
A Vulkan application starts by setting up the Vulkan API through a `VkInstance`.
57+
An instance is created by describing your application and any API extensions you
58+
will be using. After creating the instance, you can query for Vulkan supported
59+
hardware and select one or more `VkPhysicalDevice`s to use for operations. You
60+
can query for properties like VRAM size and device capabilities to select
61+
desired devices, for example to prefer using dedicated graphics cards.
62+
63+
### Step 2 - Logical device and queue families
64+
65+
After selecting the right hardware device to use, you need to create a VkDevice
66+
(logical device), where you describe more specifically which
67+
VkPhysicalDeviceFeatures you will be using, like multi viewport rendering and
68+
64 bit floats. You also need to specify which queue families you would like to
69+
use. Most operations performed with Vulkan, like draw commands and memory
70+
operations, are asynchronously executed by submitting them to a VkQueue. Queues
71+
are allocated from queue families, where each queue family supports a specific
72+
set of operations in its queues. For example, there could be separate queue
73+
families for graphics, compute and memory transfer operations. The availability
74+
of queue families could also be used as a distinguishing factor in physical
75+
device selection. It is possible for a device with Vulkan support to not offer
76+
any graphics functionality, however all graphics cards with Vulkan support today
77+
will generally support all queue operations that we're interested in.
78+
79+
### Step 3 - Window surface and swap chain
80+
81+
Unless you're only interested in offscreen rendering, you will need to create a
82+
window to present rendered images to. Windows can be created with the native
83+
platform APIs or libraries like [GLFW](http://www.glfw.org/) and [SDL](https://www.libsdl.org/).
84+
We will be using GLFW in this tutorial, but more about that in the next chapter.
85+
86+
We need two more components to actually render to a window: a window surface
87+
(VkSurfaceKHR) and a swap chain (VkSwapchainKHR). Note the `KHR` postfix, which
88+
means that these objects are part of a Vulkan extension. The Vulkan API itself
89+
is completely platform agnostic, which is why we need to use the standardized
90+
WSI (Window System Interface) extension to interact with the window manager. The
91+
surface is a cross-platform abstraction over windows to render to and is
92+
generally instantiated by providing a reference to the native window handle, for
93+
example `HWND` on Windows. Luckily, the GLFW library has a built-in function to
94+
deal with the platform specific details of this.
95+
96+
The swap chain is a collection of render targets. Its basic purpose is to ensure
97+
that the image that we're currently rendering to is different from the one that
98+
is currently on the screen. This is important to make sure that only complete
99+
images are shown. Every time we want to draw a frame we have to ask the swap
100+
chain to provide us with an image to render to. When we've finished drawing a
101+
frame, the image is returned to the swap chain for it to be presented to the
102+
screen at some point. The number of render targets and conditions for presenting
103+
finished images to the screen depends on the present mode. Common present modes
104+
are double buffering (vsync) and triple buffering. We'll look into these in the
105+
swap chain creation chapter.
106+
107+
Some platforms allow you to render directly to a display without interacting with any window manager through the `VK_KHR_display` and `VK_KHR_display_swapchain` extensions. These allow you to create a surface that represents the entire screen and could be used to implement your own window manager, for example.
108+
109+
### Step 4 - Image views and framebuffers
110+
111+
To draw to an image acquired from the swap chain, we have to wrap it into a
112+
VkImageView and VkFramebuffer. An image view references a specific part of an
113+
image to be used, and a framebuffer references image views that are to be used
114+
for color, depth and stencil targets. Because there could be many different
115+
images in the swap chain, we'll preemptively create an image view and
116+
framebuffer for each of them and select the right one at draw time.
117+
118+
### Step 5 - Render passes
119+
120+
Render passes in Vulkan describe the type of images that are used during
121+
rendering operations, how they will be used, and how their contents should be
122+
treated. In our initial triangle rendering application, we'll tell Vulkan that
123+
we will use a single image as color target and that we want it to be cleared
124+
to a solid color right before the drawing operation. Whereas a render pass only
125+
describes the type of images, a VkFramebuffer actually binds specific images to
126+
these slots.
127+
128+
### Step 6 - Graphics pipeline
129+
130+
The graphics pipeline in Vulkan is set up by creating a VkPipeline object. It
131+
describes the configurable state of the graphics card, like the viewport size
132+
and depth buffer operation and the programmable state using VkShaderModule
133+
objects. The VkShaderModule objects are created from shader byte code. The
134+
driver also needs to know which render targets will be used in the pipeline,
135+
which we specify by referencing the render pass.
136+
137+
One of the most distinctive features of Vulkan compared to existing APIs, is
138+
that almost all configuration of the graphics pipeline needs to be set in advance.
139+
That means that if you want to switch to a different shader or slightly
140+
change your vertex layout, then you need to entirely recreate the graphics
141+
pipeline. That means that you will have to create many VkPipeline objects in
142+
advance for all the different combinations you need for your rendering
143+
operations. Only some basic configuration, like viewport size and clear color,
144+
can be changed dynamically. All of the state also needs to be described
145+
explicitly, there is no default color blend state, for example.
146+
147+
The good news is that because you're doing the equivalent of ahead-of-time
148+
compilation versus just-in-time compilation, there are more optimization
149+
opportunities for the driver and runtime performance is more predictable,
150+
because large state changes like switching to a different graphics pipeline are
151+
made very explicit.
152+
153+
### Step 7 - Command pools and command buffers
154+
155+
As mentioned earlier, many of the operations in Vulkan that we want to execute,
156+
like drawing operations, need to be submitted to a queue. These operations first
157+
need to be recorded into a VkCommandBuffer before they can be submitted. These
158+
command buffers are allocated from a `VkCommandPool` that is associated with a
159+
specific queue family. To draw a simple triangle, we need to record a command
160+
buffer with the following operations:
161+
162+
* Begin the render pass
163+
* Bind the graphics pipeline
164+
* Draw 3 vertices
165+
* End the render pass
166+
167+
Because the image in the framebuffer depends on which specific image the swap
168+
chain will give us, we need to record a command buffer for each possible image
169+
and select the right one at draw time. The alternative would be to record the
170+
command buffer again every frame, which is not as efficient.
171+
172+
### Step 8 - Main loop
173+
174+
Now that the drawing commands have been wrapped into a command buffer, the main
175+
loop is quite straightforward. We first acquire an image from the swap chain
176+
with vkAcquireNextImageKHR. We can then select the appropriate command buffer
177+
for that image and execute it with vkQueueSubmit. Finally, we return the image
178+
to the swap chain for presentation to the screen with vkQueuePresentKHR.
179+
180+
Operations that are submitted to queues are executed asynchronously. Therefore
181+
we have to use synchronization objects like semaphores to ensure a correct
182+
order of execution. Execution of the draw command buffer must be set up to wait
183+
on image acquisition to finish, otherwise it may occur that we start rendering
184+
to an image that is still being read for presentation on the screen. The
185+
vkQueuePresentKHR call in turn needs to wait for rendering to be finished, for
186+
which we'll use a second semaphore that is signaled after rendering completes.
187+
188+
### Summary
189+
190+
This whirlwind tour should give you a basic understanding of the work ahead for
191+
drawing the first triangle. A real-world program contains more steps, like
192+
allocating vertex buffers, creating uniform buffers and uploading texture images
193+
that will be covered in subsequent chapters, but we'll start simple because
194+
Vulkan has enough of a steep learning curve as it is. Note that we'll cheat a
195+
bit by initially embedding the vertex coordinates in the vertex shader instead
196+
of using a vertex buffer. That's because managing vertex buffers requires some
197+
familiarity with command buffers first.
198+
199+
So in short, to draw the first triangle we need to:
200+
201+
* Create a VkInstance
202+
* Select a supported graphics card (VkPhysicalDevice)
203+
* Create a VkDevice and VkQueue for drawing and presentation
204+
* Create a window, window surface and swap chain
205+
* Wrap the swap chain images into VkImageView
206+
* Create a render pass that specifies the render targets and usage
207+
* Create framebuffers for the render pass
208+
* Set up the graphics pipeline
209+
* Allocate and record a command buffer with the draw commands for every possible
210+
swap chain image
211+
* Draw frames by acquiring images, submitting the right draw command buffer and
212+
returning the images back to the swap chain
213+
214+
It's a lot of steps, but the purpose of each individual step will be made very
215+
simple and clear in the upcoming chapters. If you're confused about the relation
216+
of a single step compared to the whole program, you should refer back to this
217+
chapter.
218+
219+
## API concepts
220+
221+
This chapter will conclude with a short overview of how the Vulkan API is
222+
structured at a lower level.
223+
224+
### Coding conventions
225+
226+
All of the Vulkan functions, enumerations and structs are defined in the
227+
`vulkan.h` header, which is included in the [Vulkan SDK](https://lunarg.com/vulkan-sdk/)
228+
developed by LunarG. We'll look into installing this SDK in the next chapter.
229+
230+
Functions have a lower case `vk` prefix, types like enumerations and structs
231+
have a `Vk` prefix and enumeration values have a `VK_` prefix. The API heavily
232+
uses structs to provide parameters to functions. For example, object creation
233+
generally follows this pattern:
234+
235+
```c++
236+
VkXXXCreateInfo createInfo{};
237+
createInfo.sType = VK_STRUCTURE_TYPE_XXX_CREATE_INFO;
238+
createInfo.pNext = nullptr;
239+
createInfo.foo = ...;
240+
createInfo.bar = ...;
241+
242+
VkXXX object;
243+
if (vkCreateXXX(&createInfo, nullptr, &object) != VK_SUCCESS) {
244+
std::cerr << "failed to create object" << std::endl;
245+
return false;
246+
}
247+
```
248+
249+
Many structures in Vulkan require you to explicitly specify the type of
250+
structure in the `sType` member. The `pNext` member can point to an extension
251+
structure and will always be `nullptr` in this tutorial. Functions that create
252+
or destroy an object will have a VkAllocationCallbacks parameter that allows you
253+
to use a custom allocator for driver memory, which will also be left `nullptr`
254+
in this tutorial.
255+
256+
Almost all functions return a VkResult that is either `VK_SUCCESS` or an error
257+
code. The specification describes which error codes each function can return and
258+
what they mean.
259+
260+
### Validation layers
261+
262+
As mentioned earlier, Vulkan is designed for high performance and low driver
263+
overhead. Therefore it will include very limited error checking and debugging
264+
capabilities by default. The driver will often crash instead of returning an
265+
error code if you do something wrong, or worse, it will appear to work on your
266+
graphics card and completely fail on others.
267+
268+
Vulkan allows you to enable extensive checks through a feature known as
269+
*validation layers*. Validation layers are pieces of code that can be inserted
270+
between the API and the graphics driver to do things like running extra checks
271+
on function parameters and tracking memory management problems. The nice thing
272+
is that you can enable them during development and then completely disable them
273+
when releasing your application for zero overhead. Anyone can write their own
274+
validation layers, but the Vulkan SDK by LunarG provides a standard set of
275+
validation layers that we'll be using in this tutorial. You also need to
276+
register a callback function to receive debug messages from the layers.
277+
278+
Because Vulkan is so explicit about every operation and the validation layers
279+
are so extensive, it can actually be a lot easier to find out why your screen is
280+
black compared to OpenGL and Direct3D!
281+
282+
There's only one more step before we'll start writing code and that's [setting
283+
up the development environment](!en/Development_environment).

0 commit comments

Comments
 (0)
0