Skip to content

Commit

Permalink
Merge pull request Overv#210 from maltekliemann/fix/hdpi-swapchain-ex…
Browse files Browse the repository at this point in the history
…tent

Fix else branch of chooseSwapExtent for HDPI/retina displays
  • Loading branch information
Overv authored Oct 27, 2020
2 parents 8f7cc95 + af27607 commit 4ece62e
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 38 deletions.
8 changes: 7 additions & 1 deletion code/06_swap_chain_creation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/07_image_views.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/08_graphics_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/09_shader_modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/10_fixed_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/11_render_passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/12_graphics_pipeline_complete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/13_framebuffers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/14_command_buffers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
8 changes: 7 additions & 1 deletion code/15_hello_triangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,13 @@ class HelloTriangleApplication {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
38 changes: 29 additions & 9 deletions en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,28 @@ VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
```

The swap extent is the resolution of the swap chain images and it's almost
always exactly equal to the resolution of the window that we're drawing to. The
range of the possible resolutions is defined in the `VkSurfaceCapabilitiesKHR`
structure. Vulkan tells us to match the resolution of the window by setting the
width and height in the `currentExtent` member. However, some window managers do
allow us to differ here and this is indicated by setting the width and height in
`currentExtent` to a special value: the maximum value of `uint32_t`. In that
case we'll pick the resolution that best matches the window within the
`minImageExtent` and `maxImageExtent` bounds.
always exactly equal to the resolution of the window that we're drawing to _in
pixels_ (more on that in a moment). The range of the possible resolutions is
defined in the `VkSurfaceCapabilitiesKHR` structure. Vulkan tells us to match
the resolution of the window by setting the width and height in the
`currentExtent` member. However, some window managers do allow us to differ here
and this is indicated by setting the width and height in `currentExtent` to a
special value: the maximum value of `uint32_t`. In that case we'll pick the
resolution that best matches the window within the `minImageExtent` and
`maxImageExtent` bounds. But we must specify the resolution in the correct unit.

GLFW uses two units when measuring sizes: pixels and
[screen coordinates](https://www.glfw.org/docs/latest/intro_guide.html#coordinate_systems).
For example, the resolution `{WIDTH, HEIGHT}` that we specified earlier when
creating the window is measured in screen coordinates. But Vulkan works with
pixels, so the swap chain extent must be specified in pixels as well.
Unfortunately, if you are using a high DPI display (like Apple's Retina
display), screen coordinates don't correspond to pixels. Instead, due to the
higher pixel density, the resolution of the window in pixel will be larger than
the resolution in screen coordinates. So if Vulkan doesn't fix the swap extent
for us, we can't just use the original `{WIDTH, HEIGHT}`. Instead, we must use
`glfwGetFramebufferSize` to query the resolution of the window in pixel before
matching it against the minimum and maximum image extent.

```c++
#include <cstdint> // Necessary for UINT32_MAX
Expand All @@ -336,7 +350,13 @@ VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = {WIDTH, HEIGHT};
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
Expand Down
24 changes: 5 additions & 19 deletions en/03_Drawing_a_triangle/04_Swap_chain_recreation.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,25 +114,11 @@ Instead I've opted to clean up the existing command buffers with the
`vkFreeCommandBuffers` function. This way we can reuse the existing pool to
allocate the new command buffers.

To handle window resizes properly, we also need to query the current size of the framebuffer to make sure that the swap chain images have the (new) right size. To do that change the `chooseSwapExtent` function to take the actual size into account:

```c++
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
} else {
int width, height;
glfwGetFramebufferSize(window, &width, &height);

VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};

...
}
}
```
Note that in `chooseSwapExtent` we already query the new window resolution to
make sure that the swap chain images have the (new) right size, so there's no
need to modify `chooseSwapExtent` (remember that we already had to use
`glfwGetFramebufferSize` get the resolution of the surface in pixels when
creating the swap chain).

That's all it takes to recreate the swap chain! However, the disadvantage of
this approach is that we need to stop all rendering before creating the new swap
Expand Down

0 comments on commit 4ece62e

Please sign in to comment.