RenderDoc経由で起動した時のみ正しく描画される

この記事は[グラフィックス全般 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/graphics)の17日目の記事です。

# はじめに
この記事は、

「実行してみたら真っ黒になっちゃった。
RenderDocでシェーダーに渡った値とか見てみよ
。。。
RenderDoc経由で起動したら描画されたんだけど」

という方向けの記事です。
お急ぎの方は下まで飛ばしてください。

# 注意
 - バージョンによって動作が異なる可能性があります。
   筆者のRenderDocはVersion v1.27です
 - 「描画されない」の原因はものすごく多いので、調査項目の一つとして考えてください。
 - RenderDocを使用して困っている方向けの記事です。RenderDocの説明はしません。
 - 当時の状況を再現したスクショを貼っています。

# 何をしようとしていたのか
Vulkanを使用して、マルチサンプリングを実装しようとして、
既に描画に成功している状態からの修正でした。

描画されてほしかったもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852552/06057f3b-25b4-3c5e-01c3-3a6a8a498590.png)

問題が発生していた時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852552/5e182538-3a1a-2c93-07c3-fb5cbe854488.png)

RenderDoc経由で起動したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852552/0536c37a-f920-e820-722d-0ebd020c4768.png)

RenderDoc経由だと描画された。。。
こんな現象が発生していました([当時のツイート](https://twitter.com/naritancorp/status/1679872470059458561))

# 仮説
 - タイミング系 (起動が少し遅れることで成功するみたいな。。。？)
 - 実行環境に依存する部分
 - メモリの確保、ステージングバッファ (vkCreateBuffer, vkAllocateMemory, memcpy...)
なども考えていましたが、カメラの位置が違うのが引っ掛かっていました

# 何が起こっていたのか
カメラの位置が違うのはviewportの問題でした。

マルチサンプリング導入前では
VkViewport構造体、VkRect2D構造体を用意して
VkPipelineViewportStateCreateInfo構造体のpViewports, pScissorsに入れていました。
```renderer_base.cpp
	VkViewport viewport;
	{
		viewport.x = 0.0f;
		viewport.y = float(_swapchainExtent.height);
		viewport.width = float(_swapchainExtent.width);
		viewport.height = -1.0f * float(_swapchainExtent.height);
		viewport.minDepth = 0.0f;
		viewport.maxDepth = 1.0f;
	}
	VkRect2D scissor = {
		{ 0, 0 },
		_swapchainExtent
	};

	VkPipelineViewportStateCreateInfo viewportCI{};
	viewportCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
	viewportCI.viewportCount = 1;
	viewportCI.pViewports = &viewport;
	viewportCI.scissorCount = 1;
	viewportCI.pScissors = &scissor;
```


マルチサンプリング導入後は
vkCmdBeginRenderPassの後に
vkCmdSetViewport, vkCmdSetScissorを呼ぶ必要がありました
```renderer_base.cpp
	VkViewport viewport{};
	viewport.x = 0.0f;
	viewport.y = (float)_swapchainExtent.height;
	viewport.width = (float)_swapchainExtent.width;
	viewport.height = -1.0f * (float)_swapchainExtent.height;
	viewport.minDepth = 0.0f;
	viewport.maxDepth = 1.0f;
	vkCmdSetViewport(_commandBuffer, 0, 1, &viewport);
 
 	VkRect2D scissor{};
	scissor.offset = { 0, 0 };
	scissor.extent = _swapchainExtent;
	vkCmdSetScissor(_commandBuffer, 0, 1, &scissor);
```
このように変える必要があり、Viewportとscissorがうまくセットできていませんでした。

# RenderDocの挙動 (忙しい方はここを読んでください)
RenderDocはどうやら描画に必要な設定が抜けているときに、
勝手にデフォルト値？を入れるような動作をするときがあり
**設定値を確認しても入っていないが、描画は成功してしまう**ということがあるようです。

ラスタライザステートでViewportsとScissorを確認することができますが、
問題が発生していたビルドでは
どのタイミングにもViewportsとScissorが入っていませんでしたが、描画はされていました

問題が発生していた時のキャプチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852552/3561938e-aa61-781f-a4be-30ec4edc1ecf.png)

直した後のキャプチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852552/b6351ddb-4822-d31f-7aa9-2cf7c5baa2cd.png)

Vulkanでは座標系がOpenGLと違って、画面の上方向がマイナスになっていたので、
OpenGLと合わせるためにHeightをマイナスに設定していました。

viewportがうまく入らなかったときに反転したのはこれが原因だと思われます。

### 追記
コメント頂いていました！ありがとうございます
>Vulkan アプリに RenderDoc を用いる際は, validation layer が何のエラーも出していないこと, つまり1つの valid usage にも違反していないことが前提になります:nerd::point_up:.

まったくその通りで、
バリデーションレイヤでエラーが出ていないことを確認しないといけませんでした！

# 参考
[https://renderdoc.org/docs/behind_scenes/vulkan_support.html](https://renderdoc.org/docs/behind_scenes/vulkan_support.html)
[https://vulkan-tutorial.com/Multisampling](https://vulkan-tutorial.com/Multisampling)
[https://blog.techlab-xe.net/post-5052/](https://blog.techlab-xe.net/post-5052/)