Kandungan
1.
2.
3.
4.
5.
6. Uniform-
7.
8.
9.
10. -
11. Multisampling
FAQ
2.
3.
4.
-
-
- Window surface
- Swap chain
- Image views
- (pipeline)
5.
- Staging
6. Uniform-
- layout
- sets
7.
- Image view image sampler
- image sampler
8.
9.
10. -
11. Multisampling
FAQ
Tukar rantai
- Memeriksa dukungan rantai swap
- Menghubungkan ekstensi
- Permintaan informasi dukungan rantai swap
- Memilih pengaturan untuk rantai swap
- Pembuatan rantai swap
- Mendapatkan gambar dari rantai swap
Vulkan tidak memiliki framebuffer default, jadi Vulkan membutuhkan infrastruktur dengan buffer tempat gambar akan dirender sebelum ditampilkan. Infrastruktur ini disebut rantai swap dan harus dibuat secara eksplisit di Vulkan. Rantai swap adalah antrian gambar yang menunggu untuk ditampilkan di layar. Program pertama-tama meminta objek
image(VkImage)
untuk digambar, dan setelah rendering, mengirimkannya kembali ke antrian. Cara kerja antrian tergantung pada pengaturannya, tetapi tugas utama rantai swap adalah menyinkronkan keluaran gambar dengan kecepatan penyegaran layar.
Memeriksa dukungan rantai swap
Beberapa kartu video khusus tidak memiliki keluaran tampilan dan oleh karena itu tidak dapat menampilkan gambar di layar. Selain itu, pemetaan layar terkait dengan sistem jendela dan bukan merupakan bagian dari inti Vulkan. Oleh karena itu, kita perlu menghubungkan ekstensi tersebut
VK_KHR_swapchain
.
Pertama
isDeviceSuitable
, mari kita ubah fungsinya untuk memeriksa apakah ekstensi tersebut didukung. Kami telah bekerja dengan daftar ekstensi yang didukung sebelumnya, jadi tidak akan ada kesulitan. Perhatikan bahwa file header Vulkan menyediakan makro praktis
VK_KHR_SWAPCHAIN_EXTENSION_NAME
yang didefinisikan sebagai "
VK_KHR_swapchain
". Keuntungan dari makro ini adalah jika Anda membuat kesalahan ejaan, kompilator akan memperingatkan Anda tentang hal itu.
Mari kita mulai dengan mendeklarasikan daftar ekstensi yang diperlukan.
const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
Untuk verifikasi tambahan, mari buat fungsi baru yang
checkDeviceExtensionSupport
dipanggil dari
isDeviceSuitable
:
bool isDeviceSuitable(VkPhysicalDevice device) {
QueueFamilyIndices indices = findQueueFamilies(device);
bool extensionsSupported = checkDeviceExtensionSupport(device);
return indices.isComplete() && extensionsSupported;
}
bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
return true;
}
Mari kita ubah badan fungsi untuk memeriksa apakah semua ekstensi yang kita butuhkan ada dalam daftar yang didukung.
bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
for (const auto& extension : availableExtensions) {
requiredExtensions.erase(extension.extensionName);
}
return requiredExtensions.empty();
}
Di sini saya biasa
std::set<std::string>
menyimpan nama-nama ekstensi yang diperlukan tetapi belum dikonfirmasi. Anda juga bisa menggunakan loop bersarang seperti dalam sebuah fungsi
checkValidationLayerSupport
. Perbedaan kinerja tidak signifikan.
Sekarang mari kita jalankan program dan pastikan bahwa kartu video kita cocok untuk membuat rantai pertukaran. Perhatikan bahwa kehadiran antrean tampilan sudah menyiratkan dukungan untuk ekstensi rantai swap. Namun, yang terbaik adalah memastikannya secara eksplisit.
Menghubungkan ekstensi
Untuk menggunakan rantai swap, Anda harus mengaktifkan ekstensi terlebih dahulu
VK_KHR_swapchain
. Untuk melakukan ini, mari ubah sedikit padding
VkDeviceCreateInfo
saat membuat perangkat logis:
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
Permintaan informasi dukungan rantai swap
Memeriksa sendiri untuk melihat apakah rantai swap tersedia tidak cukup. Pembuatan rantai swap melibatkan lebih banyak konfigurasi, jadi kami perlu meminta lebih banyak informasi.
Secara total, Anda perlu memeriksa 3 jenis properti:
- Kemampuan dasar permukaan, seperti jumlah gambar min / maks dalam rantai pertukaran, lebar dan tinggi gambar min / maks
- Format permukaan (format piksel, ruang warna)
- Mode operasi yang tersedia
Untuk bekerja dengan data ini, kami akan menggunakan struktur:
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
Sekarang mari buat fungsi
querySwapChainSupport
yang mengisi struktur ini.
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
SwapChainSupportDetails details;
return details;
}
Mari kita mulai dengan kemampuan permukaan. Mereka mudah untuk ditanyakan dan dikembalikan ke struktur
VkSurfaceCapabilitiesKHR
.
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
Fungsi ini menerima yang dibuat sebelumnya
VkPhysicalDevice
dan
VkSurfaceKHR
. Setiap kali kami meminta fungsionalitas yang didukung, kedua parameter ini akan menjadi yang pertama, karena keduanya adalah komponen kunci dari rantai swap.
Langkah selanjutnya adalah menanyakan format permukaan yang didukung. Untuk melakukan ini, mari lakukan ritual yang sudah dikenal dengan pemanggilan fungsi ganda:
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0) {
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
Pastikan Anda mengalokasikan ruang yang cukup dalam vektor untuk mendapatkan semua format yang tersedia.
Dengan cara yang sama, kami meminta mode operasi yang didukung menggunakan fungsi
vkGetPhysicalDeviceSurfacePresentModesKHR
:
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
if (presentModeCount != 0) {
details.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
}
Ketika semua informasi yang diperlukan ada dalam struktur, tambahkan fungsi
isDeviceSuitable
untuk memeriksa apakah rantai swap didukung. Untuk keperluan tutorial ini, kami akan berasumsi bahwa jika setidaknya ada satu format gambar yang didukung dan satu mode yang didukung untuk permukaan jendela, maka rantai pertukaran juga didukung.
bool swapChainAdequate = false;
if (extensionsSupported) {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
}
Anda hanya perlu meminta dukungan rantai swap setelah Anda memverifikasi bahwa ekstensi tersebut tersedia.
Baris terakhir fungsi berubah menjadi:
return indices.isComplete() && extensionsSupported && swapChainAdequate;
Memilih pengaturan untuk rantai swap
Jika
swapChainAdequate
benar, rantai swap didukung. Tetapi rantai pertukaran dapat memiliki beberapa mode. Mari menulis beberapa fungsi untuk menemukan pengaturan yang sesuai untuk membuat rantai swap yang paling efisien.
Secara total, kami menyoroti 3 jenis pengaturan:
- format permukaan (kedalaman warna)
- mode operasi (kondisi untuk mengubah bingkai di layar)
- tingkat pertukaran (resolusi gambar dalam rantai pertukaran)
Untuk setiap pengaturan, kami akan mencari beberapa nilai "ideal", dan jika tidak tersedia, kami akan menggunakan beberapa logika untuk memilih dari apa.
Format permukaan
Mari tambahkan fungsi untuk memilih format:
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
}
Nanti, kami akan memberikan anggota
formats
dari struktur
SwapChainSupportDetails
sebagai argumen.
Setiap elemen
availableFormats
berisi anggota
format
dan
colorSpace
. Bidang ini
format
menentukan jumlah dan jenis saluran. Misalnya, itu
VK_FORMAT_B8G8R8A8_SRGB
berarti kita memiliki saluran B, G, R dan alpha masing-masing 8 bit, dengan total 32 bit per piksel. Sebuah bendera
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
di lapangan
colorSpace
menunjukkan apakah ruang warna SRGB didukung. Perhatikan bahwa dalam versi spesifikasi sebelumnya, flag ini dipanggil
VK_COLORSPACE_SRGB_NONLINEAR_KHR
.
Kami akan menggunakan SRGB sebagai ruang warna. SRGB adalah standar untuk representasi warna dalam gambar, ini mereproduksi warna yang dirasakan dengan lebih baik. Itulah mengapa kami juga akan menggunakan salah satu format SRGB sebagai format warna -
VK_FORMAT_B8G8R8A8_SRGB
.
Mari kita lihat daftarnya dan periksa apakah kombinasi yang kita butuhkan tersedia:
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
Jika tidak, kami dapat mengurutkan format yang tersedia dari yang lebih cocok hingga yang kurang sesuai, tetapi dalam banyak kasus, kami dapat mengambil yang pertama dari daftar.
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
return availableFormats[0];
}
Jam kerja
Mode operasi mungkin merupakan pengaturan yang paling penting untuk rantai swap, karena ini menentukan kondisi untuk mengubah bingkai di layar.
Ada empat mode yang tersedia di Vulkan:
VK_PRESENT_MODE_IMMEDIATE_KHR
: , , , .VK_PRESENT_MODE_FIFO_KHR
: . , . , . , .VK_PRESENT_MODE_FIFO_RELAXED_KHR
: , . . .VK_PRESENT_MODE_MAILBOX_KHR
: ini adalah variasi lain dari mode kedua. Alih-alih memblokir program saat antrian penuh, gambar dalam antrian diganti dengan yang baru. Mode ini cocok untuk mengimplementasikan buffering tiga kali lipat. Dengannya, Anda dapat menghindari munculnya artefak dengan latensi rendah.
Hanya mode yang dijamin akan tersedia
VK_PRESENT_MODE_FIFO_KHR
, jadi sekali lagi kita harus menulis fungsi untuk menemukan mode terbaik yang tersedia:
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
return VK_PRESENT_MODE_FIFO_KHR;
}
Secara pribadi, saya merasa paling baik menggunakan triple buffering. Ini menghindari artefak dengan latensi rendah.
Jadi mari kita lihat daftar untuk memeriksa mode yang tersedia:
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;
}
}
return VK_PRESENT_MODE_FIFO_KHR;
}
Tingkat swap
Tetap mengkonfigurasi properti terakhir. Untuk melakukan ini, tambahkan fungsi:
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
}
Tingkat pertukaran adalah resolusi gambar dalam rantai pertukaran, yang hampir selalu cocok dengan resolusi jendela (dalam piksel) tempat gambar dirender. Kami mendapat rentang yang diizinkan dalam struktur
VkSurfaceCapabilitiesKHR
. Vulkan memberi tahu kami resolusi apa yang harus kami tetapkan menggunakan bidang
currentExtent
(cocok dengan ukuran jendela). Namun, beberapa pengelola jendela mengizinkan resolusi yang berbeda. Untuk ini, nilai khusus untuk lebar dan tinggi ditentukan
currentExtent
- nilai maksimum jenisnya
uint32_t
. Dalam hal ini, dari interval antara
minImageExtent
dan,
maxImageExtent
kami akan memilih resolusi yang paling sesuai dengan resolusi jendela. Hal utama adalah menentukan satuan pengukuran dengan benar.
GLFW menggunakan dua unit pengukuran: piksel dan koordinat layar . Jadi, resolusi
{WIDTH, HEIGHT}
yang kami tentukan saat membuat jendela diukur dalam koordinat layar. Tetapi karena Vulkan berfungsi dengan piksel, resolusi rantai swap juga harus ditentukan dalam piksel. Jika Anda menggunakan tampilan resolusi tinggi (seperti tampilan Retina Apple), koordinat layar tidak cocok dengan piksel: Karena kepadatan piksel yang lebih tinggi, resolusi jendela dalam piksel lebih tinggi daripada di koordinat layar. Karena Vulkan tidak akan memperbaiki izin rantai swap untuk kami, kami tidak dapat menggunakan izin asli
{WIDTH, HEIGHT}
. Sebaliknya, kita harus menggunakan
glfwGetFramebufferSize
untuk menanyakan resolusi jendela dalam piksel sebelum memetakannya ke resolusi gambar minimum dan maksimum.
#include <cstdint> // Necessary for UINT32_MAX
...
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)
};
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));
return actualExtent;
}
}
Fungsi
max
dan
min
digunakan untuk membatasi nilai
width
dan
height
dalam resolusi yang tersedia. Jangan lupa untuk menyertakan file header
<algorithm>
untuk menggunakan fungsinya.
Pembuatan rantai swap
Kami sekarang memiliki semua informasi yang kami butuhkan untuk membuat rantai pertukaran yang sesuai.
Mari membuat fungsi
createSwapChain
dan memanggilnya dari
initVulkan
setelah membuat perangkat logis.
void initVulkan() {
createInstance();
setupDebugMessenger();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
createSwapChain();
}
void createSwapChain() {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
}
Sekarang Anda perlu memutuskan berapa banyak objek gambar yang harus ada di rantai swap. Implementasinya menentukan jumlah minimum yang dibutuhkan untuk bekerja:
uint32_t imageCount = swapChainSupport.capabilities.minImageCount;
Namun, jika Anda hanya menggunakan minimum ini, terkadang Anda harus menunggu driver menyelesaikan operasi internal untuk mendapatkan gambar berikutnya. Oleh karena itu, lebih baik meminta setidaknya satu lebih dari minimum yang ditentukan:
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
Penting untuk tidak melebihi jumlah maksimum. Nilai
0
menunjukkan bahwa tidak ada nilai maksimum yang ditentukan.
if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
imageCount = swapChainSupport.capabilities.maxImageCount;
}
Rantai swap adalah objek Vulkan, jadi Anda perlu mengisi struktur untuk membuatnya. Awal struktur sudah tidak asing lagi bagi kita:
VkSwapchainCreateInfoKHR createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = surface;
Pertama, permukaan ditentukan, tempat rantai swap dipasang, kemudian - informasi untuk membuat objek gambar:
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
Dalam
imageArrayLayers
menentukan jumlah lapisan yang terdiri dari setiap gambar. Akan selalu ada nilai di sini
1
, kecuali, tentu saja, ini adalah gambar stereo. Bidang bit
imageUsage
menunjukkan operasi apa gambar yang diperoleh dari rantai swap akan digunakan untuk itu. Dalam tutorial, kita akan merender langsung ke mereka, tetapi Anda dapat merender ke gambar terpisah terlebih dahulu, misalnya untuk pasca-pemrosesan. Dalam hal ini, gunakan nilai
VK_IMAGE_USAGE_TRANSFER_DST_BIT
dan gunakan operasi memori untuk transfer.
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
if (indices.graphicsFamily != indices.presentFamily) {
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
} else {
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0; // Optional
createInfo.pQueueFamilyIndices = nullptr; // Optional
}
Kemudian Anda perlu menentukan cara menangani objek gambar yang digunakan di beberapa keluarga antrian. Hal ini berlaku untuk kasus di mana keluarga grafik dan keluarga tampilan adalah keluarga yang berbeda. Kami akan membuat gambar dalam antrian grafis dan kemudian mengirimkannya ke antrian tampilan.
Ada dua cara untuk memproses gambar dengan akses dari beberapa antrian:
VK_SHARING_MODE_EXCLUSIVE
: sebuah objek termasuk dalam satu keluarga antrian dan kepemilikan harus ditransfer secara eksplisit sebelum digunakan di keluarga antrian lain. Metode ini memberikan kinerja tertinggi.
VK_SHARING_MODE_CONCURRENT
: Objek dapat digunakan di beberapa keluarga antrian tanpa secara eksplisit mentransfer kepemilikan.
Jika kami memiliki banyak antrian, kami akan menggunakan
VK_SHARING_MODE_CONCURRENT
. Metode ini mengharuskan Anda untuk menentukan terlebih dahulu antara keluarga antrian mana yang akan dibagikan kepemilikan. Ini dapat dilakukan dengan menggunakan parameter
queueFamilyIndexCount
dan
pQueueFamilyIndices
. Jika keluarga antrian grafik dan keluarga antrian tampilan sama, yang lebih umum, gunakan
VK_SHARING_MODE_EXCLUSIVE
.
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
Anda dapat menentukan bahwa gambar dalam rantai pertukaran diterapkan dengan salah satu transformasi yang didukung (
supportedTransforms
dalam
capabilities
), misalnya, memutar 90 derajat searah jarum jam atau membalik secara horizontal. Untuk tidak menerapkan transformasi apa pun, tinggalkan saja
currentTransform
.
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
Bidang ini
compositeAlpha
menunjukkan apakah akan menggunakan saluran alfa untuk pencampuran dengan jendela lain di sistem jendela. Anda mungkin tidak membutuhkan saluran alfa, jadi biarkan saja
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
.
createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE;
Bidang itu
presentMode
berbicara sendiri. Jika kita meletakkannya
VK_TRUE
di lapangan
clipped
, maka kita tidak tertarik dengan hidden pixel (contohnya, jika bagian dari jendela kita tertutup oleh jendela lain). Anda selalu dapat mematikan kliping jika Anda perlu membaca piksel, tetapi untuk saat ini biarkan kliping tetap aktif.
createInfo.oldSwapchain = VK_NULL_HANDLE;
Bidang terakhir tetap -
oldSwapChain
. Jika rantai swap menjadi tidak valid, misalnya, karena perubahan ukuran jendela, itu perlu dibuat ulang dari awal dan di lapangan
oldSwapChain
tentukan link ke rantai swap lama. Ini adalah topik kompleks yang akan kita bahas di bab selanjutnya. Untuk saat ini, katakanlah kita hanya memiliki satu rantai pertukaran.
Mari tambahkan anggota kelas untuk menyimpan objek
VkSwapchainKHR
:
VkSwapchainKHR swapChain;
Sekarang Anda hanya perlu memanggil
vkCreateSwapchainKHR
untuk membuat rantai swap:
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
throw std::runtime_error("failed to create swap chain!");
}
Parameter berikut diteruskan ke fungsi: perangkat logis, informasi rantai swap, pengalokasi kustom opsional dan penunjuk untuk menulis hasil. Tidak ada kejutan. Rantai swap harus dihancurkan menggunakan
vkDestroySwapchainKHR
sebelum perangkat dihancurkan:
void cleanup() {
vkDestroySwapchainKHR(device, swapChain, nullptr);
...
}
Sekarang mari kita jalankan program untuk memastikan rantai swap berhasil dibuat. Jika Anda menerima pesan kesalahan atau pesan seperti itu
« vkGetInstanceProcAddress SteamOverlayVulkanLayer.dll»
, buka bagian FAQ .
Mari kita coba untuk menghapus garis
createInfo.imageExtent = extent;
dengan lapisan validasi diaktifkan. Salah satu level validasi akan segera mendeteksi kesalahan dan memberi tahu kami:
Mendapatkan gambar dari rantai swap
Sekarang rantai swap telah dibuat, tetap mendapatkan deskriptor VkImages . Mari tambahkan anggota kelas untuk menyimpan deskriptor:
std::vector<VkImage> swapChainImages;
Objek gambar dari rantai swap akan dihancurkan secara otomatis setelah rantai swap itu sendiri dihancurkan, jadi tidak perlu menambahkan kode pembersihan apa pun.
Segera setelah panggilan,
vkCreateSwapchainKHR
tambahkan kode untuk mendapatkan deskriptornya. Ingatlah bahwa kami hanya menentukan jumlah minimum gambar dalam rantai swap, yang berarti mungkin ada lebih banyak gambar. Oleh karena itu, pertama-tama kami meminta jumlah gambar sebenarnya menggunakan fungsi tersebut
vkGetSwapchainImagesKHR
, lalu mengalokasikan ruang yang diperlukan dalam container dan memanggilnya lagi
vkGetSwapchainImagesKHR
untuk mendapatkan deskriptornya.
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
swapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
Dan hal terakhir - simpan format dan resolusi gambar rantai swap ke dalam variabel kelas. Kami akan membutuhkannya di masa depan.
VkSwapchainKHR swapChain;
std::vector<VkImage> swapChainImages;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;
...
swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent;
Kami sekarang memiliki gambar untuk digambar dan ditampilkan. Di bab selanjutnya, kami akan menunjukkan kepada Anda cara menyiapkan gambar untuk digunakan sebagai target render, dan memulai dengan pipeline grafis dan perintah menggambar!
C ++