基于Vulkan的GPGPU计算框架Vuh

发现一个写的比较好的基于VulkanGPGPU计算框架Vuhgithub上的代码地址为:

https://github.com/Glavnokoman/vuh.git

macOS Mojave(10.14.2) 中编译方式:

$ git clone https://github.com/Glavnokoman/vuh.git

$ cd vuh/config

$ pip install --user cget

$ export PATH=/Users/`whoami`/Library/Python/2.7/bin:$PATH

$ export CGET_PREFIX=.

# 安装Vulkan相关依赖库
$ bash install_dependencies.sh

# 指定Vulkan相关环境变量,后续的CMake文件中的FindVulkan.cmake会使用这个
$ export VULKAN_SDK=`pwd`

# 我们刚刚安装的Catch2的路径,CMake需要
$ export Catch2_DIR=`pwd`/lib/cmake/Catch2

$ export ARGS=-DCatch2_DIR=$Catch2_DIR

# 安装其他依赖
$ brew install spdlog

$ brew install doxygen

$ cd ..

$ mkdir build

$ cd build

$ cmake .. $ARGS

$ make

如果编译的时候报错

Scanning dependencies of target vuh_example_spdlog
[ 60%] Building CXX object doc/examples/spdlog/CMakeFiles/vuh_example_spdlog.dir/main.cpp.o
/Users/xxx/Source/vuh/doc/examples/spdlog/main.cpp:14:27: error: no member named
      'basic_logger_mt' in namespace 'spdlog'
static auto logger = spd::basic_logger_mt("logger", "vuh.log");
                     ~~~~~^
1 error generated.
make[2]: *** [doc/examples/spdlog/CMakeFiles/vuh_example_spdlog.dir/main.cpp.o] Error 1
make[1]: *** [doc/examples/spdlog/CMakeFiles/vuh_example_spdlog.dir/all] Error 2
make: *** [all] Error 2

这个原因是由于新版本的spdlog-1.2.1变更了basic_logger_mt这个类的头文件。

在源代码的vuh/doc/examples/spdlog/main.cpp中,包含如下头文件即可:

#include <spdlog/sinks/basic_file_sink.h>

 

如果需要编译 Android 版本,那么如下方式进行编译:

$ git clone https://github.com/Glavnokoman/vuh.git

$ cd vuh/config

$ pip install --user cget

$ export PATH=/Users/`whoami`/Library/Python/2.7/bin:$PATH

$ export CGET_PREFIX=.

# 安装Vulkan相关依赖库
$ bash install_dependencies.sh

$ export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk-bundle

$ cd ..

$ mkdir build

$ cd build

$ cmake .. \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
-DANDROID_ABI="armeabi-v7a" \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_STL=c++_static \
-DANDROID_NATIVE_API_LEVEL=android-24  \
-DANDROID_TOOLCHAIN=clang \
-DVUH_BUILD_TESTS=OFF \
-DVUH_BUILD_DOCS=OFF \
-DVUH_BUILD_EXAMPLES=OFF \
-DCMAKE_CXX_FLAGS="-DVK_USE_PLATFORM_ANDROID_KHR=1 -DVULKAN_HPP_TYPESAFE_CONVERSION=1 -I$ANDROID_NDK_HOME/sources/third_party/vulkan/src/include/"

# 最后生成 libvuh.so ,然后自己写代码调用这个库即可,简单的直接修改代码中的例子即可
$ make

注意最后几个参数,文档,测试用例,例子都不参与编译,原因在于这几个工程不适合 Android 上运行,最后需要定义几个 C++ 的编译宏,否则编译不通过。

如果上面编译的时候,提示如下错误信息:

[ 20%] Building CXX object src/CMakeFiles/vuh.dir/instance.cpp.o
vuh/src/instance.cpp:127:33: error: incompatible operand
      types ('vuh::debug_reporter_t' (aka 'unsigned int (*)(unsigned int,
      VkDebugReportObjectTypeEXT, unsigned long long, unsigned int, int, const
      char *, const char *, void *) __attribute__((pcs("aapcs-vfp")))') and
      'auto (*)(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t,
      size_t, int32_t, const char *, const char *, void *) -> VkBool32' (aka
      'auto (*)(unsigned int, VkDebugReportObjectTypeEXT, unsigned long long,
      unsigned int, int, const char *, const char *, void *) -> unsigned int'))
           , _reporter(report_callback ? report_callback : debugReporter)
                                       ^ ~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~
vuh/src/instance.cpp:128:49: warning: field '_reporter' is
      uninitialized when used here [-Wuninitialized]
           , _reporter_cbk(registerReporter(_instance, _reporter))
                                                       ^
1 warning and 1 error generated.
make[2]: *** [src/CMakeFiles/vuh.dir/instance.cpp.o] Error 1
make[1]: *** [src/CMakeFiles/vuh.dir/all] Error 2
make: *** [all] Error 2

这个错误的原因是 vuh/src/instance.cpp 中定义

/// Default debug reporter used when user did not care to provide his own.
static auto debugReporter(
        VkDebugReportFlagsEXT , VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t
        , const char*                pLayerPrefix
        , const char*                pMessage
        , void*                      /*pUserData*/
        )-> VkBool32
{
    std::cerr << "[Vulkan]:" << pLayerPrefix << ": " << pMessage << "\n";
    return VK_FALSE;
}

的时候,缺少 VKAPI_ATTR 这个宏。貌似只有在 Android 平台上这个宏被赋值,其他平台都是空。因此其他平台编译的时候,没有这个参数也是没问题的。

修改后的结果为:

/// Default debug reporter used when user did not care to provide his own.
static auto VKAPI_ATTR debugReporter(
        VkDebugReportFlagsEXT , VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t
        , const char*                pLayerPrefix
        , const char*                pMessage
        , void*                      /*pUserData*/
        )-> VkBool32
{
    std::cerr << "[Vulkan]:" << pLayerPrefix << ": " << pMessage << "\n";
    return VK_FALSE;
}

VKAPI_ATTR 这个宏在 vk_platform.h这个文件中被定义,定义的具体内容如下:

/*
***************************************************************************************************
*   Platform-specific directives and type declarations
***************************************************************************************************
*/

/* Platform-specific calling convention macros.
 *
 * Platforms should define these so that Vulkan clients call Vulkan commands
 * with the same calling conventions that the Vulkan implementation expects.
 *
 * VKAPI_ATTR - Placed before the return type in function declarations.
 *              Useful for C++11 and GCC/Clang-style function attribute syntax.
 * VKAPI_CALL - Placed after the return type in function declarations.
 *              Useful for MSVC-style calling convention syntax.
 * VKAPI_PTR  - Placed between the '(' and '*' in function pointer types.
 *
 * Function declaration:  VKAPI_ATTR void VKAPI_CALL vkCommand(void);
 * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
 */
#if defined(_WIN32)
    // On Windows, Vulkan commands use the stdcall convention
    #define VKAPI_ATTR
    #define VKAPI_CALL __stdcall
    #define VKAPI_PTR  VKAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
    #error "Vulkan isn't supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
    // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
    // calling convention, i.e. float parameters are passed in registers. This
    // is true even if the rest of the application passes floats on the stack,
    // as it does by default when compiling for the armeabi-v7a NDK ABI.
    #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
    #define VKAPI_CALL
    #define VKAPI_PTR  VKAPI_ATTR
#else
    // On other platforms, use the default calling convention
    #define VKAPI_ATTR
    #define VKAPI_CALL
    #define VKAPI_PTR
#endif

Vulkan官方API文档Vulkan® 1.0.95 - A Specification

Vulkan官方API文档 Vulkan® 1.0.95 - A Specification 对于开发者来说,非常有用。

由于官方网站访问非常缓慢,建议下载PDF版本到本地来查看。

官方文档地址:  Vulkan® 1.0.95 - A Specification - Khronos Group

官方PDF版本地址: Vulkan® 1.0.95 - A Specification - Khronos Group

本站的一份PDF版拷贝
继续阅读Vulkan官方API文档Vulkan® 1.0.95 - A Specification

Vulkan中的"#version 430 core"的理解

最近在学习Vulkan,结果在查看示例代码的时候:

#version 430 core
layout (local_size_x = 64) in;


layout(std430, binding=4 ) buffer INFO 
{
        vec2 info[];
};


void main()
{
    uint gid = gl_GlobalInvocationID.x;
    info[gid].x += 1.0;
    info[gid].y += 1.0;
    memoryBarrier();
}

对于如下语句出现了疑问

#version 430 core

这句话的意思是OpenGL必须是4.3以及以上的版本。

那么是不是意味着,如果设备上的OpenGL低于这个版本,那么我们编写的Vulkan代码就不能执行呢?

答案是否定的,目前我们开发Vulkan默认是使用GLSLOpenGL Shading Language)语言,然后编译完成后的操作符被直接映射成Vulkan的定义操作符。

换句话说,我们只要执行如下命令,

$ glslangValidator xx.comp --target-env vulkan1.0

能编译通过,就可以随意指定#version的版本。

这个版本号仅仅是GLSL语言在进行语法检查的时候需要的,而Vulkan是没有这个版本号需要的。

如果不使用GLSL语言编写,上述的#version应该都不会在语法中出现。

继续阅读Vulkan中的"#version 430 core"的理解