Skip to content
Snippets Groups Projects
Commit f52e8fa6 authored by n0F4x's avatar n0F4x
Browse files

Create swapchain

parent 119fb814
No related branches found
No related tags found
No related merge requests found
Pipeline #50723 passed
......@@ -148,3 +148,268 @@ Ilyenkor *clamp*-elni kell az általunk használni kívánt értéket a felszín
A `surface_capabilities`-t majd az ablakfelszín segítségével fogjuk megkapni, a `framebuffer_size`-t pedig maga az ablak adja.
### Surface format
A következő lépés, hogy megadjuk a képek pixelformátumát.
Ez lehetne például a jól ismert RGBA (red, green, blue, alpha), ahol minden *color channel* 8 bit-et kap.
Azonban a legtöbb képernyő a BGRA-t támogatja jól.
A másik tulajdonság a színcsatornákban lévő értékek eloszlása/linearitása.
Mivel a szemünk nem lineáris intenzitással érzékeli az adott értékekhez tartozó fényt, ezért érdemes egy nem lineáris *color space* formátumot választani.
*(lásd. [gamma correction](https://en.wikipedia.org/wiki/Gamma_correction))*
??? example "Példa kód"
```cpp title="Swapchain.cpp"
[[nodiscard]]
static auto choose_swapchain_surface_format(
const vk::SurfaceKHR surface,
const vk::PhysicalDevice physical_device
) -> vk::SurfaceFormatKHR
{
const auto available_surface_formats{ physical_device.getSurfaceFormatsKHR(surface) };
for (const auto& surface_format : available_surface_formats) {
if (surface_format.format == vk::Format::eB8G8R8A8Srgb
&& surface_format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
{
return surface_format;
}
}
for (const auto& surface_format : available_surface_formats) {
if (surface_format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
return surface_format;
}
}
return available_surface_formats.front();
}
```
### Képek száma
Ajánlott a minimum támogatott értéktől legalább eggyel nagyobb számú képet használni a swapchain-hez.
Illetve arra is figyelnünk kell, hogy ne lépjük át a maximumot.
(Ha a maximum-hoz definiált érték 0, akkor nincs maximum.)
??? example "Kódrészlet"
```cpp title="Swapchain.cpp"
[[nodiscard]]
static auto get_min_image_count(const vk::SurfaceCapabilitiesKHR& surface_capabilities
) noexcept -> uint32_t
{
uint32_t image_count = surface_capabilities.minImageCount + 1;
if (surface_capabilities.maxImageCount > 0
&& image_count > surface_capabilities.maxImageCount)
{
image_count = surface_capabilities.maxImageCount;
}
return image_count;
}
```
### Presentation mode
Még fontos kiemelni az [előadásdiákban](./Megjelenítés.pptx) is említett megjelenítési módokat (`Mailbox`, `Fifo`, ...).
Ahol nem annyira fontos az energiafogyasztás, ott erősen ajánlott a *Mailbox*.
??? example "Hogyan ellenőrizzük, hogy tudunk-e *Mailbox*-ot használni?"
```cpp
[[nodiscard]]
static auto choose_swapchain_present_mode(
const vk::SurfaceKHR surface,
const vk::PhysicalDevice physical_device
) -> vk::PresentModeKHR
{
const auto present_modes{ physical_device.getSurfacePresentModesKHR(surface) };
return std::ranges::find(present_modes, vk::PresentModeKHR::eMailbox)
!= std::cend(present_modes)
? vk::PresentModeKHR::eMailbox
: vk::PresentModeKHR::eFifo;
}
```
A jelenlegi megoldásból kivettem ezt az opciót az egyszerűség kedvéért.
*Fifo*-t fogunk használni, mert az se rossz, és alapértelmezetten mindenhol támogatott.
### Létrehozás
A választott képformátumot és méretet tároljuk el, mert még később szükségünk lesz rá.
```cpp title="Swapchain.hpp"
class Swapchain {
public:
// ...
[[nodiscard]]
auto get() const noexcept -> vk::SwapchainKHR;
[[nodiscard]]
auto extent() const noexcept -> vk::Extent2D;
[[nodiscard]]
auto format() const noexcept -> vk::Format;
private:
vk::Extent2D m_extent;
vk::Format m_format;
vk::UniqueSwapchainKHR m_swapchain;
explicit Swapchain(
const vk::Extent2D& extent,
vk::Format format,
vk::UniqueSwapchainKHR&& swapchain
) noexcept;
};
```
```cpp title="Swapchain.cpp"
auto Swapchain::get() const noexcept -> vk::SwapchainKHR
{
return m_swapchain.get();
}
auto Swapchain::extent() const noexcept -> vk::Extent2D
{
return m_extent;
}
auto Swapchain::format() const noexcept -> vk::Format
{
return m_format;
}
Swapchain::Swapchain(
const vk::Extent2D& extent,
vk::Format format,
vk::UniqueSwapchainKHR&& swapchain
) noexcept
: m_extent{ extent },
m_format{ format },
m_swapchain{ std::move(swapchain) }
{}
```
Végül hozzuk létre a swapchain-t.
```cpp title="Swapchain.hpp"
class Swapchain {
public:
// ...
[[nodiscard]]
static auto create(
vk::SurfaceKHR surface,
vk::PhysicalDevice physical_device,
uint32_t queue_family_index,
vk::Device device,
const vk::Extent2D& framebuffer_size
) -> std::optional<Swapchain>;
// ...
```
0 szélességű/magasságú képet nem tudunk létrehozni, és nincs is értelme.
Ezért ebben az esetben visszaadunk egy `nullopt`-ot.
(Azaz az opcionális visszatérési értékben nem lesz semmi.)
```cpp title="Swapchain.cpp"
auto Swapchain::create(
const vk::SurfaceKHR surface,
const vk::PhysicalDevice physical_device,
const uint32_t queue_family_index,
const vk::Device device,
const vk::Extent2D& framebuffer_size
) -> std::optional<Swapchain>
{
const auto surface_capabilities{ physical_device.getSurfaceCapabilitiesKHR(surface) };
const auto extent = choose_extent(framebuffer_size, surface_capabilities);
if (extent.width == 0 || extent.height == 0) {
return std::nullopt;
}
const auto surface_format{ choose_swapchain_surface_format(surface, physical_device) };
auto swapchain{ create_swapchain(
surface,
queue_family_index,
device,
surface_capabilities,
extent,
surface_format
) };
return Swapchain{ extent, surface_format.format, std::move(swapchain) };
}
```
```cpp title="Swapchain.cpp"
[[nodiscard]]
static auto create_swapchain(
const vk::SurfaceKHR surface,
const uint32_t queue_family_index,
const vk::Device device,
const vk::SurfaceCapabilitiesKHR& surface_capabilities,
const vk::Extent2D extent,
const vk::SurfaceFormatKHR surface_format
) -> vk::UniqueSwapchainKHR
{
const std::array queue_family_indices{ queue_family_index };
const vk::SwapchainCreateInfoKHR create_info{
.surface = surface,
.minImageCount = get_min_image_count(surface_capabilities),
.imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = vk::ImageUsageFlagBits::eColorAttachment,
.imageSharingMode = vk::SharingMode::eExclusive,
.queueFamilyIndexCount = static_cast<uint32_t>(queue_family_indices.size()),
.pQueueFamilyIndices = queue_family_indices.data(),
.preTransform = surface_capabilities.currentTransform,
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
.presentMode = vk::PresentModeKHR::eFifo,
.clipped = vk::True
};
return device.createSwapchainKHRUnique(create_info);
}
```
??? note "Mi ez a sok paraméter amit megadtunk a swapchain-nek?"
- `imageArrayLayers` -
Ez mindig egy, hacsak nem egy [sztereoszkopikus](https://en.wikipedia.org/wiki/Stereoscopy) alkalmazást fejlesztünk.
- `imageUsage` -
Ezzel megadjuk, milyen módon fogjuk majd használni a képeket.
Mivel jelenleg csak rajzolni fogunk rájuk, ezért *color attachment*-ként fogjuk őket használni, de akár *transfer*-hez is használhatnánk például *post-processing*-hez.
- `imageSharingMode` -
Több családból származó queue-k esetén beállíthatjuk, hogy egy kép melyik család tulajdona legyen.
Mi csak csak egy queue-t használunk, ezért exkluzívan ő uralja a képet.
Más esetben megadhatunk konkurrens tulajdon módot is.
- `preTransform`
A képekhez hozzárendelhetünk valamilyen transformációt is.
Amennyiben ezzel nem szeretnénk élni, úgy a `surface_capabilities.currentTransform`-ot kell használni.
- `compositeAlpha`
Ezzel megadhatjuk, hogy átfedésben lévő ablakok hogyan hassanak a képre (blending).
- `clipped`
Amennyiben egy másik ablak miatt fedésbe kerülnek bizonyos pixelek, eldönthetjük, hogy megtartsuk-e őket későbbi műveletektre.
```cpp title="Renderer.cpp"
Renderer::Renderer(const Window& window)
// ...
m_swapchain{ Swapchain::create(
m_surface.get(),
m_physical_device,
m_queue_family_index,
m_device.get(),
window.framebuffer_size()
) }
{}
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment