初めてのVulkanプログラミング step3 スワップチェーンの作成

[目次に戻る](https://qiita.com/tositada_nakada/items/db0f01c1c8c2945f786b)

ソースコードは以下の場所に置いておきます。各自のバージョンに合わせたプロパティ設定をしてから自由にご利用ください。

[GitHub](https://github.com/nakadasanda/vulkanAppaddcal2018)

##スワップチェーン
VUlkanでは、標準のデフォルトのフレームバッファがありません。画面に表示したい場合、レンダリング可能な一連のバッファーを持つインフラをを作成する必要があります。これらのバッファとプロパティは、**スワップチェーン**と呼ばれます。

##スワップチェーンのサポート確認
**vkGetPhysicalDeviceSurfaceSupportKHR()**関数はあるデバイスが、スワップチェーンをサポートしているか確認します。   


```cpp
	VkBool32 surfaceSupport;
	vkGetPhysicalDeviceSurfaceSupportKHR(_renderer->GetVulkanPhysicalDevice(), 0, _surface, &surfaceSupport);

```
##デバイス拡張
スワップチェーンはGPUが描写する画像バッファーのインフラであるため、GPUレベルの拡張が必要です。
そのためサンプルコードでは**VK_KHR_SWAPCHAIN_EXTENSION_NAME**を挿入しています

使用するデバイス拡張を**vkDeviceCreateInfo**に入れる

```cpp
	std::vector<const char*>	_device_extensions;
	_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
//vkdevicecreateinfoに挿入
	device_create_info.enabledExtensionCount = _device_extensions.size();
	device_create_info.ppEnabledExtensionNames = _device_extensions.data();

```
##プロパティの取得
画面に表示するための互換性がないため、スワップチェーンが利用可能かどうかの確認だけでは、スワップチェーンを使用できません。
スワップチェーンに必要な情報としては、3種類の情報が必要です。

・基本的なサーフェスの機能 (スワップチェーンの画面の大きさ、バッファの数、etc...)
・描写フォーマット (24ビットカラー、白黒画像、赤だけの画面、etc...)
・利用可能なプレゼンテーションモード 

```cpp
	//基本的なサーフェスの機能

	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, _surface, &_surface_capabilities);
	
	//描写フォーマット
	uint32_t format_count = 0;
	vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &format_count, nullptr);
	std::vector<VkSurfaceFormatKHR>formats(format_count);
	vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &format_count, formats.data());
	std::cout << "DeviceSurfaceFormats: " << format_count << std::endl;
	for (int i = 0; i < format_count;i++) {
		std::cout << "Format: " << formats[i].format << std::endl;
	}

	//利用可能なプレゼンテーションモード
	uint32_t present_mode_count;
	vkGetPhysicalDeviceSurfacePresentModesKHR(_renderer->GetVulkanPhysicalDevice(),_surface, &present_mode_count, nullptr);
	std::vector<VkPresentModeKHR>present_mode_list(present_mode_count);
	vkGetPhysicalDeviceSurfacePresentModesKHR(_renderer->GetVulkanPhysicalDevice(), _surface, &present_mode_count, present_mode_list.data());
	std::cout << "DeviceSurfaceFormats: " << present_mode_count << std::endl;
	for (int i = 0; i < present_mode_count; i++) {
		std::cout << "support present mode: " << present_mode_list[i] << std::endl;
	}

```

##プレゼンテーションモード

プレゼンテーションモードは、実際に画面に描写するときのアルゴリズムを指定します。
vulkanでは、以下の4つがあります。

#####VK_PRESENT_MODE_IMMEDIATE_KHR

送信された画像をすぐに表示します。

#####VK_PRESENT_MODE_FIFO_KHR
ディスプレイのリフレッシュレートを保持するために単一のキューを使用します。新しい要求がキューにおくられ、１つの要求がキューの先頭からでます。キューがいっぱいになったときには、待ち時間が発生します。

#####VK_PRESENT_MODE_MAILBOX_KHR
キューがいっぱいになったときにアプリケーションをブロックせずに、すぐに表示します。トリプルバッファリングに実装する際に使用します。これによりダブルバッファリングを使う場合よりも滑らかにに表示することができる可能性があります。その代わりに処理が重くなる可能性があります

![presentmode.JPG](https://qiita-image-store.s3.amazonaws.com/0/251306/649cc052-0539-97a5-06cc-040197dc8a77.jpeg)


##スワップチェーンの作成
実行時に必要な情報がそろったのでスワップチェーンを作成します

まずサーフェスを指定します。

```cpp
	VkSwapchainCreateInfoKHR swapchain_create_info = {};
	swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
	swapchain_create_info.pNext = nullptr;
	swapchain_create_info.flags = 0;
	swapchain_create_info.surface = _surface;
```

基本的なサーフェスの機能を指定します
**imageformat** B8G8R8A8...フルビットカラーです。UNORM...8ビットカラーだけど0.0~1.0fとして変換するよ
**color space**...色空間を指定
**imageArrayLayers**...マルチビュー/ステレオサーフェスの数 非立体画像の場合は１

```cpp
	swapchain_create_info.minImageCount = _surface_capabilities.minImageCount;
	swapchain_create_info.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; //_surface_format.format
	swapchain_create_info.imageColorSpace = _surface_format.colorSpace;
	swapchain_create_info.imageExtent.width = _surface_size_x;
	swapchain_create_info.imageExtent.height = _surface_size_y;
	swapchain_create_info.imageArrayLayers = 1;
```

描写フォーマットのオプションを指定します

**imageUsage** ... imageの使い方 、
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT...Image viewを作成して、colorを含んだ,Imageをフレームバッファーに渡す。

**sharingmode** ...Imageのキューへの共有
一つのキューファミリーにシェアする。

**queueFamilyIndexCount**... 他のキューファミリーと共有する場合は、入れる。SHARING_MODE_CONCURRENTの時
**preTransform**...画像を表示する際に画像を回転する。
**compositeAlpha**...Alpha値の値.デフォルトで1.0にする.

```cpp
	swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
	swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
	swapchain_create_info.queueFamilyIndexCount = 0;
	swapchain_create_info.pQueueFamilyIndices = nullptr;
	swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
	swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
```

プレゼンテーションモードを指定します
**clipped**...表示よりも外側にあるrenderは破棄しますか？。true

```cpp
	swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
	swapchain_create_info.clipped =VK_TRUE;
	swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
	
```

最後vkCreateSwapchainKHR関数を呼び出し完成です

```cpp
	 vkCreateSwapchainKHR(gpu,&swapchain_create_info,nullptr,&_swapchain);
```



## 連絡先

tweeter: [tositada_nakada](https://twitter.com/nakadasanda17)
mail: nakadasanda@outlook.com

## 寄付

paypal: [tositada_nakada](https://www.paypal.me/nakadasanda)
Amazon:[欲しいものリスト](http://amzn.asia/fGpGuJo)