メモ

備忘録や趣味など

ANGLEを使ってOpenGL ES をVulkanに変換して動かす

ANGLEとは

ANGLE(Almost Native Graphics Layer Engine)は、OpenGL ES API呼び出しを各プラットフォームで利用可能なハードウェアでサポートされたAPIの1つに変換してくれる。最初はWindowsWebGLレンダリングする方法として始まったらしい。現在のサポートはこちらで確認できる。

目標

Windowsで、OpenGL ESをそのままVulkanで実行できるようにしたい。

必要なツール(2021年8月時点)

VisualStudio 2019、Windows 10SDK、Python3.9、GLFW、ANGLE、chromiumのdepot_tools

導入手順

1 gclientやGN、ninjaが使えるように、depot_toolsをこちらからダウンロードする

2 depot_toolsへのパスを通す(※ここではPythonのパスより前に設定する)

3 VisualStudio 2019、Windows 10 SDKが利用可能か確認

4 ソースを取得する

set DEPOT_TOOLS_WIN_TOOLCHAIN=0

git clone https://chromium.googlesource.com/angle/angle

cd angle

python scripts/bootstrap.py

gclient sync

git checkout master

5 ninjaビルド用のディレクトリを作成する

gn gen out/Debug

ここではビルド前に様々なビルドオプションを設定することが可能。

6 ninjaでビルドする(時間がかかります)

autoninja -C out/Debug

ここではVisual Studioソリューション生成して、ビルドすることも可能。

7 out/Debugに以下のライブラリが生成されていることを確認

  • libEGL.dll

  • libEGL.dll.lib

  • libGLESv2.dll

  • libGLESv2.dll.lib

8 GLFWをダウンロード

ドキュメントによると、ANGLEのバックエンドをVulkanに変更するにはEGL拡張のEGL_ANGLE_platform_angleを使えばよい。eglGetPlatformDisplayEXT(EGLenum platform, void native_display, const EGLint attrib_list) のようにして設定することが可能で、ANGLE内にサンプルコードもある。しかしGLFWを使っている場合は初期化の前に以下のように設定するだけで簡単にバックエンドを変更できる。

glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, GLFW_ANGLE_PLATFORM_TYPE_VULKAN);

参考

自分が確認したところ、GLFWのWindowsパッケージではANGLEがサポートされていないようだったので、GLFWのmain branchから直接cloneしてコンパイルした。

9 Visual Studio 2019でプロジェクト作成&ANGLEから必要なものを持ってくる。自分は以下のように配置した

AngleTest

  └main.cpp

.sln

lib

  ├GLES2

    ├include

      └ANGLEのincludeの中身

    └lib

      └x64

        └libGLESv2.dll.lib、libEGL.dll.lib

  └GLFW

x64

  └Debug

    └.exe

アプリケーションと同じ階層に以下の.dllファイルを配置する

  • libEGL.dll

  • libGLESv2.dll

  • absl.dll

  • libc++.dll

  • VkLayer_khronos_validation.dll

  • vulkan-1.dll

  • zlib.dll

10 Additional Include/Library Directory と Additional Dependenciesを以下のように設定する 

Additional Include Directories

  • ..\lib\GLFW\include

  • ..\lib\GLES2\include

Additional Library Directories

  • ..\lib\GLFW\lib

  • ..\lib\GLES2\lib\x64

Additional Dpendencies

  • glfw3.lib

  • libEGL.dll.lib

  • libGLESv2.dll.lib

11 テスト用のOpenGL ESは以下の通り

#include <iostream>




#define GLFW_INCLUDE_ES3

#define GL_GLEXT_PROTOTYPES




#include "GLFW/glfw3.h"




int main(){




    int Width = 800;

    int Height = 600;




    //バックエンドにVulkanを選択

    glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, GLFW_ANGLE_PLATFORM_TYPE_VULKAN);




    if (glfwInit() == GL_FALSE)

    {

        throw std::runtime_error("failed to init GLFW");

    }




    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);

    glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);

    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);

    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);




    auto window = glfwCreateWindow(Width, Height, "App", nullptr, nullptr);

    if (!window)

    {

        throw std::runtime_error("failed to create Window");

    }




    glfwMakeContextCurrent(window);

    glfwSwapInterval(1);




    while (glfwWindowShouldClose(window) == GL_FALSE)

    {

        glfwPostEmptyEvent();

        glViewport(0, 0, Width, Height);

        glClear(GL_COLOR_BUFFER_BIT);

        glClearColor(0.f, 0.f, 0.5f, 1.f);

        glfwSwapBuffers(window);

        glfwWaitEvents();

    }




    glfwDestroyWindow(window);

    glfwTerminate();




    return -1;

}

12 Vulkanで動いているか確認したいのでRenderDocを使う

デフォルトではOpenGL ESエミュレータのフックが有効でキャプチャできないので、以下のように無効にしておく。

set RENDERDOC_HOOK_EGL=0

参考

13 実行結果

備考

  • 元々OpenGLのプロジェクトを無理やりOpenGL ESにしようとしたとき、GLEWを使っていると初期化に失敗するので、GLES2/gl2.h、GLES2/gl2ext.hから直接OpenGL ESの関数を呼び出した。

参考

ソースコードこちらにあります。

  • 何か間違い、気になる箇所等あれば言って下さると嬉しいです