DirectX11 Map UnmapのGPUによる挙動の違いについて

私が使っていたノートPCで
DirectX11のAPIをよく理解していなかったために起きた事象を記録します
ノートPCでGPUが付属している環境の方でDX10以降の学習をされている方は
同じ過ちをしないことを望みます。

ここで使っているFBXの描画処理は下記サイトの方法を参考にしました
http://gameworkslab.jp/プログラム記事まとめ/ライブラリ/

3Dモデルについてはこちらのものをお借りしています
http://6b.u5ch.com/others/downloads/index.html

■使用PC 下記の構成のモデルを利用しています
・SurfaceBook2 
　・プロセッサ:Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz (8CPUs), ～2.1GHz
　・GPU 0:Intel(R) UHD Graphics620
　・GPU 1:NVIDIA GeForce GTX1060
■環境
・VisualStudio2017 ,  DirectX11 C++

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/fe3b1ea5-4072-0686-04bb-ed9c58fa84ae.png" width=33%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/f99f4763-232b-a48f-293d-9388bd803f49.png" width=33%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/31a046d7-c101-287c-693c-e01c3db1ec16.png" width=33%>

SurfaceBook2では、下記画像のようにExeファイルに対して右クリックを押した時、
インテルのGPUとNvidiaのGPUを切り替えることができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/ff8b47bd-4964-d844-62a0-c23d68ecc375.png" width=40%>　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/1cbf8a23-ef15-4f2e-ff6e-7776da9a1e9c.png" width=50%>

これを切り変えた時に、個人で作っていた描画プログラムが不正になっていたことがわかりました

(左)Intel(R) UHD Graphics620で描画　調査のためモデルを拡大表示(右)GeForce GTX1060:小さく表示される
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/34915fea-9410-9068-770d-a0ec5d0c692d.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/f3c14570-2855-8029-d726-77c98ea1c321.png" width=50%>

GeForce GTX1060のドライバーを最新にしても変化がなく、
参考にしていた　http://gameworkslab.jp/プログラム記事まとめ/ライブラリ/
ここのDirectX9のプログラムで両GPU切り替えた場合に同モデルが正常に描画できていることがわかり、
DirectX11のコード側が誤っていると推測されました

DirectX11はVisualStudioのデバッグ機能でシェーダプログラムのパイプラインを見ることができるので、
調べてみます
(左)Intel(R) UHD Graphics620で描画　 (右)GeForce GTX1060:
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/aa6509e5-2a2a-c00b-7f7b-769dbd7f4ff0.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/78fe4bea-e82a-d326-2ca8-cf120ff213c4.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/4853ae95-0f97-3d4e-dc72-72ca82cf3570.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/e24c2cfd-49a6-150d-dbda-bc32dba3d3e0.png" width=50%>

比較してわかった上記情報をもとに原因箇所を特定

Intel(R) UHD Graphics620　はD3D11_MAPPED_SUBRESOURCE の pDataの値を読み込めている
![09_intel_vtxlock.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/1e920943-3e66-839d-850c-6cec2e2ab8bb.png)

NVIDIA GeForce GTX1060　では読み込めていない
![010_nvidia_vtxlock.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/cecd4244-15c5-8cbc-5173-2ff5c0959a0a.png)

結果をもとに修正をしたスキニング部分の処理の例です (右側が両GPUで正常に動作するコード)
![11_gpudiff.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/7c51d9fe-03c1-b24c-5867-fecfebdd73f1.png)

(ここでnew,deleteしているのはもちろん好ましくありません。後日処理をうつしました)
両GPU共に意図通りの描画結果となりました　(サボテンの位置が違うのはここでは気にしなくていいです)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/10b7403f-2b4b-f583-de4f-5aa7edc57acd.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292510/0e9cddee-3d99-51b5-4820-24089e97c3e7.png" width=50%>

■上記結果からまとめ
・インテルの統合型グラフィックスGPUはオンボードなため、本来は読みだせないであろうmap APIから得たD3D11_MAPPED_SUBRESOURCEのpData で情報を読み込めてしまっていたように推察され、
書き換え可能なものと勘違いしていたと考えられる。(おそらくオンボードGPUで起きうる)
 →これを逆に理解した上で利用することで、
　統合型GPUに対する最適な処理を書くことが可能ともいえそうです

・CPUでメッシュのスキニングをやりたい場合は
　上記理由より、モデル毎に頂点情報を重複して保持することになる
　(のでGPUスキニングに移そうと思います)

■教訓
・D3D11_MAP_WRITE_DISCARDフラグはGPU側は全領域更新を想定しているため
　Map,Unmapで操作したい情報はCPUで保持して書き換える
・VisualStudioのグラフィックスデバッグで最初から頂点情報が不正である場合、
　前段階でこういった事象がおきていないか疑う


やっとSurfaceBook2のGTX1060が使えそうです...