Vulkan で描画した結果を OpenGL の世界で使用することができます。
これには NVIDIA 拡張を使用するので、現時点においては NVIDIA のグラフィックスボードを使用していることが条件になります。
今回のこの拡張の名前は、 GL_NV_draw_vulkan_image というもので、将来的に他のメーカーも対応するようになればいいなと思います。
何が出来るのか
GL_NV_draw_vulkan_image という拡張は何を行ってくれるのかというと、
Vulkan を使用して描画した結果を OpenGL の描画で使用するといったことを可能にしてくれます。
詳細には Vulkan の Image を用いて、 OpenGL のカレントのフレームバッファに対して矩形を描画します。
これにより Vulkan でオフスクリーンに描画した結果を (FBOを用いて) OpenGL のテクスチャにするといったこともできます。
API の仕様は、以下の URL にて記載があるので興味のある人はご確認ください。
NV_draw_vulkan_image
実装紹介
この拡張を使用して OpenGL のデフォルトフレームバッファに Vulkan のレンダーターゲット(オフスクリーン)として書いたものを描画するといったことをやってみました。
コード自体はたいしたことが無いので、処理の流れを紹介します。とはいっても、先ほどの API 仕様を読めばわかることだったりしますが・・・。
まず必要になるものとして OpenGL と Vulkan の協調動作のために Vulkan 側で VkSemaphore を作成する必要があります。
- Vulkan 側で処理を始めて良いか
- OpenGL 側で処理を始めて良いか
このために、 「Vulkan 側で処理を始めて良いか」 = renderFinishGL, 「OpenGL 側で処理を始めて良いか」 = renderFinishVK としてセマフォを作成しました。初回は Vulkan で描画をさせるために renderFinishGL はシグナル状態として設定しておきます。
擬似コードとして以下のような感じです。必要な部分のみ紹介しているので関連するパラメータは実装の際に適切に設定してください.
render() { // Vulkan で描画. VkSubmitInfo submitInfo; submitInfo.pWaitSemaphores = &renderFinishGL; submitInfo.pSignalSemaphores = &renderFinishVK; vkQueueSubmit( submitInfo ); // Vulkan 描画の完了を待つ . glWaitVkSemaphoreNV( renderFinishVK ); // OpenGL で描画. glSignalVkSemaphoreNV( renderFinishGL ); }
このような感じで、 OpenGL と Vulkan の描画の同期をとります。
OpenGL の描画の部分で Vulkan Image を描画するには、 glDrawVkImageNV 関数を使用します。
void DrawVkImageNV( GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z、 GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
これを用いると (x0, y0) – (x1,y1) の矩形に、 vkImage の画像を描画することができます。画像を使用する範囲は (s0,t0)-(s1,t1) です。
Vulkan で描画して、OpenGL のデフォルトフレームバッファについて描画した結果以下のようになりました。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawVkImageNV( image, 0, 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f); glSignalVkSemaphoreNV( renderFinishGL ); glfwSwapBuffers(window);
まとめ
Vulkan で描画した結果を OpenGL で使うことを試してみました。意外と簡単に画像を持ってこれることがわかりました。書き割りのような背景を Vulkan で描画してあとは OpenGL で、なんてこもとできそうです。