Skip to content

Commit 6ba6891

Browse files
committed
Adjust documentation of first three chapters to the corresponding sources.
1 parent 0aad08a commit 6ba6891

4 files changed

Lines changed: 267 additions & 201 deletions

File tree

attachments/02_validation_layers.cpp

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -92,36 +92,38 @@ class HelloTriangleApplication
9292
}
9393

9494
// Check if the required layers are supported by the Vulkan implementation.
95-
auto layerProperties = context.enumerateInstanceLayerProperties();
96-
for (auto const &requiredLayer : requiredLayers)
95+
auto layerProperties = context.enumerateInstanceLayerProperties();
96+
auto unsupportedLayerIt = std::ranges::find_if(requiredLayers,
97+
[&layerProperties](auto const &requiredLayer) {
98+
return std::ranges::none_of(layerProperties,
99+
[requiredLayer](auto const &layerProperty) { return strcmp(layerProperty.layerName, requiredLayer) == 0; });
100+
});
101+
if (unsupportedLayerIt != requiredLayers.end())
97102
{
98-
if (std::ranges::none_of(layerProperties,
99-
[requiredLayer](auto const &layerProperty) { return strcmp(layerProperty.layerName, requiredLayer) == 0; }))
100-
{
101-
throw std::runtime_error("Required layer not supported: " + std::string(requiredLayer));
102-
}
103+
throw std::runtime_error("Required layer not supported: " + std::string(*unsupportedLayerIt));
103104
}
104105

105106
// Get the required extensions.
106-
auto requiredExtensions = getRequiredExtensions();
107+
auto requiredExtensions = getRequiredInstanceExtensions();
107108

108109
// Check if the required extensions are supported by the Vulkan implementation.
109110
auto extensionProperties = context.enumerateInstanceExtensionProperties();
110-
for (auto const &requiredExtension : requiredExtensions)
111+
auto unsupportedPropertyIt =
112+
std::ranges::find_if(requiredExtensions,
113+
[&extensionProperties](auto const &requiredExtension) {
114+
return std::ranges::none_of(extensionProperties,
115+
[requiredExtension](auto const &extensionProperty) { return strcmp(extensionProperty.extensionName, requiredExtension) == 0; });
116+
});
117+
if (unsupportedPropertyIt != requiredExtensions.end())
111118
{
112-
if (std::ranges::none_of(extensionProperties,
113-
[requiredExtension](auto const &extensionProperty) { return strcmp(extensionProperty.extensionName, requiredExtension) == 0; }))
114-
{
115-
throw std::runtime_error("Required extension not supported: " + std::string(requiredExtension));
116-
}
119+
throw std::runtime_error("Required extension not supported: " + std::string(*unsupportedPropertyIt));
117120
}
118121

119-
vk::InstanceCreateInfo createInfo{
120-
.pApplicationInfo = &appInfo,
121-
.enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()),
122-
.ppEnabledLayerNames = requiredLayers.data(),
123-
.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()),
124-
.ppEnabledExtensionNames = requiredExtensions.data()};
122+
vk::InstanceCreateInfo createInfo{.pApplicationInfo = &appInfo,
123+
.enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()),
124+
.ppEnabledLayerNames = requiredLayers.data(),
125+
.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()),
126+
.ppEnabledExtensionNames = requiredExtensions.data()};
125127
instance = vk::raii::Instance(context, createInfo);
126128
}
127129

@@ -130,16 +132,18 @@ class HelloTriangleApplication
130132
if (!enableValidationLayers)
131133
return;
132134

133-
vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);
134-
vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
135-
vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{
136-
.messageSeverity = severityFlags,
137-
.messageType = messageTypeFlags,
138-
.pfnUserCallback = &debugCallback};
135+
vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
136+
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
137+
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);
138+
vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
139+
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
140+
vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{.messageSeverity = severityFlags,
141+
.messageType = messageTypeFlags,
142+
.pfnUserCallback = &debugCallback};
139143
debugMessenger = instance.createDebugUtilsMessengerEXT(debugUtilsMessengerCreateInfoEXT);
140144
}
141145

142-
std::vector<const char *> getRequiredExtensions()
146+
std::vector<const char *> getRequiredInstanceExtensions()
143147
{
144148
uint32_t glfwExtensionCount = 0;
145149
auto glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
== Vulkan-hpp and designated initializers
66

7-
NOTE: We are going to use designated initializers introduced with C++ 20. By default,
8-
Vulkan-hpp uses a different way of initializing and we need to explicitly enable this
9-
by using the `VULKAN_HPP_NO_STRUCT_CONSTRUCTORS` define.
7+
NOTE: We are going to use designated initializers introduced with C++ 20.
8+
By default, Vulkan-hpp uses a different way of initializing and we need to explicitly enable this by using the `VULKAN_HPP_NO_STRUCT_CONSTRUCTORS` define.
109

11-
This provides a better meaning towards what each option relates to in the structures that we're depending upon. For this tutorial, said define is declared in the xref:../../02_Development_environment.adoc#cmake[CMake build setup].
10+
This provides a better meaning towards what each option relates to in the structures that we're depending upon.
11+
For this tutorial, said define is declared in the xref:../../02_Development_environment.adoc#cmake[CMake build setup].
1212

1313
If you use a different build setup or want to write code from scratch, you need to manually define this before including the Vulkan-hpp headers like this:
1414
[,c++]
@@ -21,9 +21,8 @@ If you use a different build setup or want to write code from scratch, you need
2121

2222
== General structure
2323

24-
In the previous chapter, you've created a Vulkan project with all the proper
25-
configurations and tested it with the sample code. In this chapter, we're starting
26-
from scratch with the following code:
24+
In the previous chapter, you've created a Vulkan project with all the proper configurations and tested it with the sample code.
25+
In this chapter, we're starting from scratch with the following code:
2726

2827
[,c++]
2928
----
@@ -60,12 +59,15 @@ private:
6059
}
6160
};
6261
63-
int main() {
64-
HelloTriangleApplication app;
65-
66-
try {
62+
int main()
63+
{
64+
try
65+
{
66+
HelloTriangleApplication app;
6767
app.run();
68-
} catch (const std::exception& e) {
68+
}
69+
catch (const std::exception& e)
70+
{
6971
std::cerr << e.what() << std::endl;
7072
return EXIT_FAILURE;
7173
}
@@ -108,11 +110,10 @@ we no longer need it. In c{pp} it is possible to perform automatic resource
108110
management using https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization[RAII]
109111
or smart pointers provided in the `<memory>` header. This tutorial is an attempt
110112
to make Vulkan easier to work with, and demonstrate modern Vulkan
111-
programming. This tutorial will not only use RAII with smart pointers, it
112-
will endeavor to demonstrate the latest methods and extensions which should
113-
hopefully make Vulkan a joy to use. Just because we enjoy working with
114-
low level graphics APIs, we shouldn't make the bar too high to learn how
115-
to do so. Where appropriate, we will discuss concerns for resource
113+
programming. This tutorial will not only use RAII, it will endeavor to demonstrate the
114+
latest methods and extensions which should hopefully make Vulkan a joy to use. Just
115+
because we enjoy working with low level graphics APIs, we shouldn't make the bar too
116+
high to learn how to do so. Where appropriate, we will discuss concerns for resource
116117
management for freeing resources. However, for this tutorial, we'll
117118
demonstrate that we can get pretty far with a basic destructor to clean up
118119
after our work.
@@ -132,7 +133,7 @@ of code that looks like this:
132133

133134
[,c++]
134135
----
135-
vkInstance instance;
136+
VkInstance instance;
136137
VkApplicationInfo appInfo{};
137138
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
138139
appInfo.pApplicationName = "Hello Triangle";
@@ -146,8 +147,8 @@ createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
146147
createInfo.pApplicationInfo = &appInfo;
147148
createInfo.enabledExtensionCount = 0;
148149
createInfo.ppEnabledExtensionNames = nullptr;
149-
150150
createInfo.enabledLayerCount = 0;
151+
createInfo.ppEnabledLayerNames = nullptr;
151152
152153
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
153154
throw std::runtime_error("failed to create instance!");
@@ -160,11 +161,11 @@ can be directly replaced by this:
160161

161162
[,c++]
162163
----
163-
constexpr vk::ApplicationInfo appInfo{ .pApplicationName = "Hello Triangle",
164-
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
165-
.pEngineName = "No Engine",
166-
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
167-
.apiVersion = vk::ApiVersion14 };
164+
constexpr vk::ApplicationInfo appInfo{.pApplicationName = "Hello Triangle",
165+
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
166+
.pEngineName = "No Engine",
167+
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
168+
.apiVersion = vk::ApiVersion14};
168169
169170
vk::InstanceCreateInfo createInfo{
170171
.pApplicationInfo = &appInfo

en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ Now, to create an instance, we'll first have to fill in a struct with some
3333
information about our application. This data is technically optional, but it may
3434
provide some useful information to the driver to optimize our specific
3535
application, (e.g., because it uses a well-known graphics engine with
36-
certain special behavior). This struct is called `VkApplicationInfo`:
36+
certain special behavior). This struct is called `vk::ApplicationInfo`:
3737

3838
[,c++]
3939
----
40-
void createInstance() {
41-
constexpr vk::ApplicationInfo appInfo{ .pApplicationName = "Hello Triangle",
42-
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
43-
.pEngineName = "No Engine",
44-
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
45-
.apiVersion = vk::ApiVersion14 };
40+
void createInstance()
41+
{
42+
constexpr vk::ApplicationInfo appInfo{.pApplicationName = "Hello Triangle",
43+
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
44+
.pEngineName = "No Engine",
45+
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
46+
.apiVersion = vk::ApiVersion14};
4647
}
4748
----
4849

@@ -67,13 +68,13 @@ vk::InstanceCreateInfo createInfo{
6768
};
6869
----
6970

70-
The first parameter is the flags for the structure, the second is the
71-
appInfo that we just created. The next is an array of layers being
72-
requested, and the final is an array of the desired global extensions. As
73-
mentioned in the overview chapter, Vulkan is a platform-agnostic API, which
74-
means that you need an extension to interface with the window system. GLFW
75-
has a handy built-in function that returns the extension(s) it needs to do
76-
that which we can pass to the struct:
71+
This structure has a member named flags, which we will handle later in this chapter.
72+
The member pApplicationInfo points to the appInfo that we just created.
73+
The next is an array of layers being requested, and the final is an array of
74+
the desired global extensions. As mentioned in the overview chapter, Vulkan
75+
is a platform-agnostic API, which means that you need an extension to interface
76+
with the window system. GLFW has a handy built-in function that returns the
77+
extension(s) it needs to do that which we can pass to the struct:
7778

7879
[,c++]
7980
----
@@ -105,7 +106,7 @@ important layers to enable for any project. We'll talk about this more
105106
in-depth in the next chapter, so leave this empty for now.
106107

107108
We've now specified everything Vulkan needs to create an instance, and we can
108-
finally issue the `vk:CreateInstance` call:
109+
finally create the vk::raii::Instance:
109110

110111
[,c++]
111112
----
@@ -122,25 +123,30 @@ Vulkan follow is:
122123
* Returns the pointer to the raii constructed object.
123124

124125
If everything went well, then the handle to the instance was returned. We can
125-
check that everything worked by use of c{pp} exceptions, or a more advanced
126-
way is to turn off exceptions by defining VULKAN_HPP_NO_EXCEPTIONS. Then
126+
check that everything worked by use of c{pp} exceptions. If you can't use c{pp}
127+
exceptions, you can turn them off by defining VULKAN_HPP_NO_EXCEPTIONS. Then
127128
the calls will return a std::tuple with a VKResult and the returned object.
128129
Here's an example of checking for errors in Vulkan calls:
129130

130131
[,c++]
131132
----
132-
try {
133+
try
134+
{
133135
vk::raii::Context context;
134136
vk::raii::Instance instance(context, vk::InstanceCreateInfo{});
135137
vk::raii::PhysicalDevice physicalDevice = instance.enumeratePhysicalDevices().front();
136138
vk::raii::Device device(physicalDevice, vk::DeviceCreateInfo{});
137139
138140
// Use Vulkan objects
139141
vk::raii::Buffer buffer(device, vk::BufferCreateInfo{});
140-
} catch (const vk::SystemError& err) {
142+
}
143+
catch (const vk::SystemError& err)
144+
{
141145
std::cerr << "Vulkan error: " << err.what() << std::endl;
142146
return 1;
143-
} catch (const std::exception& err) {
147+
}
148+
catch (const std::exception& err)
149+
{
144150
std::cerr << "Error: " << err.what() << std::endl;
145151
return 1;
146152
}
@@ -150,43 +156,48 @@ Or use the tuple:
150156

151157
[,c++]
152158
----
153-
auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr);
154-
155-
if (result == vk::Result::eErrorOutOfDateKHR)
156-
{
157-
recreateSwapChain();
158-
return;
159-
}
160-
if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR)
161-
{
162-
throw std::runtime_error("failed to acquire swap chain image!");
163-
}
159+
vk::raii::Context context;
160+
...
161+
auto instanceRV = context.createInstance(...);
162+
if (!instanceRV.has_value())
163+
{
164+
std::cerr << "Error: Instance creation failed with " << vk::to_string(instanceVR.result) << std::endl;
165+
std::exit(EXIT_FAILURE);
166+
}
167+
vk::raii::Instance instance = std::move(instanceRV.value);
168+
...
169+
auto physicalDevicesRV = instance.enumeratePhysicalDevices();
170+
if (!physicalDevicesRV.hasValue())
171+
{
172+
std::cerr << "Error: Enumerating PhysicalDevices failed with " << vk::to_string(physicalDevicesRV) << std::endl;
173+
std::exit(EXIT_FAILURE);
174+
}
175+
vk::raii::PhysicalDevice physicalDevice = std::move(physicalDevicesRV.value.front());
176+
...
164177
----
165178

166-
Those examples are from later parts of our tutorial, this is just an example
179+
This example is from later parts of our tutorial, it is just an example
167180
of how to check for errors in all of your calls.
168181

169-
== Encountered VK_ERROR_INCOMPATIBLE_DRIVER:
170-
If using macOS with the latest MoltenVK sdk, you may get `VK_ERROR_INCOMPATIBLE_DRIVER`
171-
returned from `vkCreateInstance`. According to the
182+
== Encountered vk::Result::eErrorIncompatibleDriver:
183+
If using macOS with the latest MoltenVK sdk, you may get `vk::Result::eErrorIncompatibleDriver`,
184+
thrown from `vk::raii::createInstance` or the vk::raii::Instance constructor. According to the
172185
https://vulkan.lunarg.com/doc/sdk/1.3.216.0/mac/getting_started.html[Getting Start Notes].
173-
Beginning with the 1.3.216 Vulkan SDK, the `VK_KHR_PORTABILITY_subset`
174-
extension is mandatory.
186+
Beginning with the 1.3.216 Vulkan SDK, the `VK_KHR_PORTABILITY_subset` extension is mandatory.
175187

176188
To get over this error, first add the `vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR` bit
177-
to `VkInstanceCreateInfo` struct flags, then add
178-
`vk::KHRPortabilityEnumerationExtensionName` to instance enabled
179-
extension list.
189+
to `vk::InstanceCreateInfo` struct flags, then add `vk::KHRPortabilityEnumerationExtensionName`
190+
to instance enabled extension list.
180191

181192
Typically, the code could be like this:
182193

183194
[,c++]
184195
----
185-
constexpr vk::ApplicationInfo appInfo{ .pApplicationName = "Hello Triangle",
186-
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
187-
.pEngineName = "No Engine",
188-
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
189-
.apiVersion = vk::ApiVersion14 };
196+
constexpr vk::ApplicationInfo appInfo{.pApplicationName = "Hello Triangle",
197+
.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
198+
.pEngineName = "No Engine",
199+
.engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
200+
.apiVersion = vk::ApiVersion14};
190201
vk::InstanceCreateInfo createInfo{
191202
.flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR,
192203
.pApplicationInfo = &appInfo,
@@ -204,17 +215,16 @@ That makes sense for essential extensions like the window system interface, but
204215
what if we want to check for optional functionality?
205216

206217
To retrieve a list of supported extensions before creating an instance, there's
207-
the `vkEnumerateInstanceExtensionProperties` function. We can call it on the
208-
context object; it returns a vector of the extensions available, which
209-
allows us to filter extensions by a specific validation layer, which we'll
210-
ignore for now.
218+
the `vk::raii::Context::enumerateInstanceExtensionProperties` function. It returns
219+
a vector of the available extensions, which allows us to filter extensions by a
220+
specific validation layer, which we'll ignore for now.
211221

212222
[,c++]
213223
----
214224
auto extensions = context.enumerateInstanceExtensionProperties();
215225
----
216226

217-
Each `VkExtensionProperties` struct contains the name and version of an
227+
Each `vk::ExtensionProperties` struct contains the name and version of an
218228
extension. We can list them with a simple for loop (`\t` is a tab for
219229
indentation):
220230

@@ -228,10 +238,7 @@ for (const auto& extension : extensions) {
228238
----
229239

230240
You can add this code to the `createInstance` function if you'd like to provide
231-
some details about the Vulkan support. As a challenge, try to create a function
232-
that checks if all the extensions returned by
233-
`glfwGetRequiredInstanceExtensions` are included in the supported extensions
234-
list.
241+
some details about the Vulkan support.
235242

236243
Before continuing with the more complex steps after instance creation, it's time
237244
to evaluate our debugging options by checking out xref:./02_Validation_layers.adoc[validation layers].

0 commit comments

Comments
 (0)