angle折腾笔记

Author Avatar
Kanglai Qian 5月 07, 2022

时隔多年重新编译angle,主要是为了PC上能模拟ES3.1,特别是最好能支持VT相关操作。本来不抱希望,毕竟angle文档上写的很清楚,目前GL/GLES/Vulkan Backend都只支持到ES 3.1,ES 3.2还处于in progress。

但是突然发现EXT_copy_image这个扩展在Vulkan Backend上已经被支持Vulkan: Add support for EXT_copy_image,瞬间觉得有戏就折腾了下。

Compile Angle

DevSetup里描述的还是比较清晰的,这里只记录下有坑的地方。

Proxy

由于大家都知道的国情,记得给git和gclient都打开代理,避免烦恼

git config --global http.proxy "127.0.0.1:1087"
git config --global https.proxy "127.0.0.1:1087"
set HTTP_PROXY=http://127.0.0.1:1087
set HTTPS_PROXY=http://127.0.0.1:1087

Error Code 9009

拉取仓库完成之后,gclient会自动调用脚本设置一些东西,然后我就遇到一个非常奇怪的错误

python3 third_party\depot_tools\update_depot_tools_toggle.py --disable

看了下这个脚本非常简单,直接运行了下也没出错——搜了下9009这个错误编码是和VS有关,但是我还没到这一步呢orz

最后突然发现我本地测试犯傻了,顺手就是调用的python…改成python3之后弹出了Microsoft Store,好吧又是老问题了,修改下环境变量里的PATH即可(具体可参考解决 win10 命令行下运行 python 弹出 Windows 应用商店)。

Windows SDK

这个问题说实话是我一开始万万没想到这么坑的… angle编译需要Windows SDK 10.0.20348.0及对应的Debugger Tool

for debug_file, is_optional in debug_files:
full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu, debug_file)
if not os.path.exists(full_path):
if is_optional:
continue
else:
raise Exception('%s not found in "%s"\r\nYou must install '
'Windows 10 SDK version 10.0.20348.0 including the '
'"Debugging Tools for Windows" feature.' %
(debug_file, full_path))

咱就跟着版本来一个呗,万万没想到VS Installer提示安装成功但是实际安装失败…遇事不决就手动,运行vcvarsall.bat amd64 10.0.20348.0结果提示SDK incomplete。网上查了圈还真有类似问题,Visual Studio Installer does not provide SDK 10.0.20348.0/Not able to install any previous version of VS. Download fails because on invalid signature,简直了emmm

然后我自作聪明了一发——那要不试试我本地已有的Windows SDK?当然事后发现就是自己坑自己 修改了下setup_toolchain.py强行指定老版本

args.append('10.0.19041.0')

这样之后就可以成功生成工程gn gen out/Debug --sln=angle-debug --ide=vs2019。然而下一个暴击就是编译出错

1>..\..\third_party\llvm-build\Release+Asserts\bin\clang-cl.exe /c ../../src/libEGL/egl_loader_autogen.cpp /Foobj/libEGL_egl_loader/egl_loader_autogen.obj /nologo /showIncludes:user "-imsvcC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\ATLMFC\include" "-imsvcC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include" "-imsvcC:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um" "-imsvcC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" "-imsvcC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared" "-imsvcC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um" "-imsvcC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt" "-imsvcC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt" -DUSE_AURA=1 -D_HAS_NODISCARD -D_CRT_NONSTDC_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS "-DCR_CLANG_REVISION=\"llvmorg-15-init-9074-gc62b014d-1\"" -DCOMPONENT_BUILD -D_LIBCPP_ABI_UNSTABLE -D_LIBCPP_ENABLE_NODISCARD -D_LIBCPP_NO_AUTO_LINK -D__STD_C -D_CRT_RAND_S -D_CRT_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_DEPRECATE -D_ATL_NO_OPENGL -D_WINDOWS -DCERT_CHAIN_PARA_HAS_EXTRA_FIELDS -DPSAPI_VERSION=2 -DWIN32 -D_SECURE_ATL -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_UNICODE -DUNICODE -DNTDDI_VERSION=NTDDI_WIN10_FE -D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00 -D_DEBUG -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DANGLE_IS_WIN -DANGLE_USE_EGL_LOADER -DGL_GLES_PROTOTYPES=1 -DEGL_EGL_PROTOTYPES=1 -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -I../../buildtools/third_party/libc++ -I../../include -I../../src /W4 -Wimplicit-fallthrough -Wunreachable-code-aggressive -Wthread-safety /WX -Wno-missing-field-initializers -Wno-unused-parameter -Wloop-analysis -Wno-unneeded-internal-declaration -Wno-nonportable-include-path -Wno-null-pointer-subtraction -Wenum-compare-conditional -Wno-psabi -Wno-ignored-pragma-optimize -Wno-unqualified-std-cast-call -Xclang -no-opaque-pointers -Wmax-tokens -Wshadow -fno-delete-null-pointer-checks -fno-ident -fcolor-diagnostics -fmerge-all-constants -fcrash-diagnostics-dir=../../tools/clang/crashreports -mllvm -instcombine-lower-dbg-declare=0 /clang:-ffp-contract=off -fcomplete-member-pointers /Gy /FS /bigobj /utf-8 /Zc:twoPhase /Zc:sizedDealloc- /D__WRL_ENABLE_FUNCTION_STATICS__ -fmsc-version=1916 /Zc:dllexportInlines- -m64 -msse3 /Brepro -Wno-builtin-macro-redefined -D__DATE__= -D__TIME__= -D__TIMESTAMP__= -ffile-compilation-dir=. -no-canonical-prefixes -ftrivial-auto-var-init=pattern /Od /Ob0 /GF /Z7 -gcodeview-ghash -Xclang -fuse-ctor-homing /guard:cf,nochecks /MDd -Wheader-hygiene -Wstring-conversion -Wtautological-overlap-compare -Wexit-time-destructors -Wglobal-constructors /we4244 /we4312 /we4456 /we4458 /we4715 /we4800 /we4838 -Wbad-function-cast -Wconditional-uninitialized -Wextra-semi-stmt -Wfloat-conversion -Winconsistent-missing-destructor-override -Wmissing-field-initializers -Wnewline-eof -Wnon-virtual-dtor -Wredundant-parens -Wreturn-std-move -Wshadow -Wshadow-field -Wtautological-type-limit-compare -Wundefined-reinterpret-cast -Wunneeded-internal-declaration -Wunused-but-set-variable -Wsuggest-destructor-override -Wsuggest-override -Wparentheses -Wrange-loop-analysis -Wstrict-prototypes -Wunreachable-code-aggressive -Wshorten-64-to-32 -Wno-undefined-bool-conversion -Wno-tautological-undefined-compare /std:c++17 -Wno-trigraphs /Zc:alignedNew- /TP /GR- -I../../buildtools/third_party/libc++/trunk/include /Fd"obj/libEGL_egl_loader_cc.pdb"

1>C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um\fileapi.h(1105,10): error : unknown type name 'FILE_INFO_BY_HANDLE_CLASS'

稍微看了下minwinbase.hFILE_INFO_BY_HANDLE_CLASS的定义,发现是编译参数里的-DNTDDI_VERSION=NTDDI_WIN10_FE这个宏不存在导致的…好吧好吧,那看来还真是不能用老版本的Windows SDK。

在M$官网扒拉到了Windows SDK and emulator archive,发现下下来已经是Windows SDK 10.0.20348.1了,不管了先装为敬——emmm为啥安装文件夹是对应到10.0.20348.0? 把前面修改的setup_toolchain.py回退之后重新生成工程,终于编译成功~

Compile Option

编译出来的libGLESv2.dlllibEGL.dll覆盖回去之后发现启动失败,LoadLibrary对应Error code 126,这种情况赌五毛肯定是有依赖库丢了…用Dependencies验证了下确实。那么用gn args out/Debug修改一下编译设置,第三方库强制static link就好了。

is_component_build = false

ps. 最后打包应该使用Release版本,直接用gn gen out/Release --sln=angle-release --ide=vs2019配合gn args out/Release

is_component_build = false
is_debug = false
angle_assert_always_on = false

GLES Runtime

这里主要参考了EGLWindow.cpp,主要涉及两个细节:

  • 强制打开ES 3.1,这里和PVR有所不同,如果不指定EGL_CONTEXT_MINOR_VERSION_KHR,那么默认是走的3.0
    EGLint ContextAttributes[] =
    {
    EGL_CONTEXT_CLIENT_VERSION, 3,
    EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
    EGL_CONTEXT_MINOR_VERSION_KHR, 1,
    EGL_NONE
    }
    EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttributes);
  • 使用Vulkan Backend
    EGLAttrib DisplayAttributes[] =
    {
    EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
    EGL_NONE
    };
    EglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, hDC, DisplayAttributes);

别的没啥要改的了,一把梭使用glCopyImageSubDataEXT就都没问题了。比较遗憾的是PC上依然只支持BC系列,不能使用ETC(完美模拟手机计划失败)。看了下代码,其实是这个条件还没实现完整导致的orz

angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
ImageHelper *srcImage,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
ImageHelper *dstImage,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
// ...
if (CanCopyWithTransferForCopyImage(contextVk->getRenderer(), srcImage, srcTilingMode, dstImage,
destTilingMode))
{
// ...
}
else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
{
// The source and destination image formats may be using a fallback in the case of RGB
// images. A compute shader is used in such a case to perform the copy.
// ...
}
else
{
// No support for emulated compressed formats.
UNIMPLEMENTED();
ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
}

return angle::Result::Continue;
}

Conclusion

后来顺手测试了下PVR版本的libGLESv2.dll,才发现其实也有EXT_copy_image支持,所以VT的效果也是对的。

但是折腾了这么一大圈还是有价值的: 一方面使用起来的体验天差地别,angle vulkan backend能稳定跑到60fps,而pvr和angle dx11版只有可怜的10fps不到。另一个非常大的收益在于方便调试,毕竟有对应PDB和源代码之后,可以一路F11进去看各种GL_ERROR的原因,特别关注ValidateXXX函数里面的检查: