Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 948d6d3

Browse files
committed
Clarify use of std::optional (fixes #147)
1 parent 1906fe6 commit 948d6d3

1 file changed

Lines changed: 98 additions & 13 deletions

File tree

en/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.md

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -201,23 +201,77 @@ commands or one that only allows memory transfer related commands.
201201
We need to check which queue families are supported by the device and which one
202202
of these supports the commands that we want to use. For that purpose we'll add a
203203
new function `findQueueFamilies` that looks for all the queue families we need.
204-
Right now we'll only look for a queue that supports graphics commands, but we
205-
may extend this function to look for more at a later point in time.
206204
207-
This function will return the indices of the queue families that satisfy certain
208-
desired properties. The best way to do that is using a structure where we use `std::optional` to track if an index was found:
205+
Right now we are only going to look for a queue that supports graphics commands,
206+
so the function could look like this:
207+
208+
```c++
209+
uint32_t findQueueFamilies(VkPhysicalDevice device) {
210+
// Logic to find graphics queue family
211+
}
212+
```
213+
214+
However, in one of the next chapters we're already going to look for yet another
215+
queue, so it's better to prepare for that and bundle the indices into a struct:
209216

210217
```c++
211218
struct QueueFamilyIndices {
212-
std::optional<uint32_t> graphicsFamily;
219+
uint32_t graphicsFamily;
220+
};
213221

214-
bool isComplete() {
215-
return graphicsFamily.has_value();
216-
}
222+
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
223+
QueueFamilyIndices indices;
224+
// Logic to find queue family indices to populate struct with
225+
return indices;
226+
}
227+
```
228+
229+
But what if a queue family is not available? We could throw an exception in
230+
`findQueueFamilies`, but this function is not really the right place to make
231+
decisions about device suitability. For example, we may *prefer* devices with a
232+
dedicated transfer queue family, but not require it. Therefore we need some way
233+
of indicating whether a particular queue family was found.
234+
235+
It's not really possible to use a magic value to indicate the nonexistence of a
236+
queue family, since any value of `uint32_t` could in theory be a valid queue
237+
family index including `0`. Luckily C++17 introduced a data structure to
238+
distinguish between the case of a value existing or not:
239+
240+
```c++
241+
#include <optional>
242+
243+
...
244+
245+
std::optional<uint32_t> graphicsFamily;
246+
247+
std::cout << std::boolalpha << graphicsFamily.has_value() << std::endl; // false
248+
249+
graphicsFamily = 0;
250+
251+
std::cout << std::boolalpha << graphicsFamily.has_value() << std::endl; // true
252+
```
253+
254+
`std::optional` is a wrapper that contains no value until you assign something
255+
to it. At any point you can query if it contains a value or not by calling its
256+
`has_value()` member function. That means that we can change the logic to:
257+
258+
```c++
259+
#include <optional>
260+
261+
...
262+
263+
struct QueueFamilyIndices {
264+
std::optional<uint32_t> graphicsFamily;
217265
};
266+
267+
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
268+
QueueFamilyIndices indices;
269+
// Assign index to queue families that could be found
270+
return indices;
271+
}
218272
```
219273
220-
Note that this also requires including `<optional>`. We can now begin implementing `findQueueFamilies`:
274+
We can now begin to actually implement `findQueueFamilies`:
221275
222276
```c++
223277
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
@@ -252,10 +306,6 @@ for (const auto& queueFamily : queueFamilies) {
252306
indices.graphicsFamily = i;
253307
}
254308
255-
if (indices.isComplete()) {
256-
break;
257-
}
258-
259309
i++;
260310
}
261311
```
@@ -265,13 +315,48 @@ check in the `isDeviceSuitable` function to ensure that the device can process
265315
the commands we want to use:
266316

267317
```c++
318+
bool isDeviceSuitable(VkPhysicalDevice device) {
319+
QueueFamilyIndices indices = findQueueFamilies(device);
320+
321+
return indices.graphicsFamily.has_value();
322+
}
323+
```
324+
325+
To make this a little bit more convenient, we'll also add a generic check to the
326+
struct itself:
327+
328+
```c++
329+
struct QueueFamilyIndices {
330+
std::optional<uint32_t> graphicsFamily;
331+
332+
bool isComplete() {
333+
return graphicsFamily.has_value();
334+
}
335+
};
336+
337+
...
338+
268339
bool isDeviceSuitable(VkPhysicalDevice device) {
269340
QueueFamilyIndices indices = findQueueFamilies(device);
270341
271342
return indices.isComplete();
272343
}
273344
```
274345

346+
We can now also use this for an early exit from `findQueueFamilies`:
347+
348+
```c++
349+
for (const auto& queueFamily : queueFamilies) {
350+
...
351+
352+
if (indices.isComplete()) {
353+
break;
354+
}
355+
356+
i++;
357+
}
358+
```
359+
275360
Great, that's all we need for now to find the right physical device! The next
276361
step is to [create a logical device](!en/Drawing_a_triangle/Setup/Logical_device_and_queues)
277362
to interface with it.

0 commit comments

Comments
 (0)