• 备胎计划002 跨平台shader编译方案实践


    Unity 和 Unreal 作为流行的商业引擎,引擎这个东西,最主要的特点就是抽象。其中关于Shader部分,他们都做了比较好的抽象,使用者不需关注每个平台的shader不同,写一次,build各个平台。

    这是当今游戏引擎的一个重要标配,Unity 和 Unreal 都自己做了大量的工作,网上也有人分析过Unity和Unreal各自的方案。


    替代方案

    现如今,开源世界也有一些方案来处理这个问题了


    主要是两条线

    1.DirectXShaderCompiler + spirvcross


    2.glsllang +spirvcross


    方案一,DirectXShaderCompiler 是微软开源的hlsl编译器,最新的版本增加了一个编译开关,重编译后可获取将hlsl 编译为 spirv 的能力,然后通过spirvcross项目编译成各种各样的东西


    方案二,glsllang 是 Khronos 官方的 for vulkan 的 glsl编译器,他负责将glsl编译为spirv,然后通过spirvcross项目编译成各种各样的东西


    这两个方案使用的编写语言分别是hlsl 和 glsl(方案二其实也支持hlsl,但是资料比较少,我还没有实验出来),都是用sprivcross来跨平台

    这里就要解释一下什么是spirv

    爷爷Khronos: 是图形标准化组织,OPENGL就是他们制定的,然后在微软搞dx12,苹果搞metal的时候,他们也推出了新一代图形API标准,就是Vulkan。

    爹Vulkan:大伯OPENGL,二伯OPENGL ES

    儿子spirv:而vulkan使用的shader二进制格式就是spirv

    因为opengl 和opengles 的时代,都没有发展二进制格式,爷爷制定标准的时候就想把他打造成一个通用的格式,所以spirv实际上是个很通用的执行格式(想象一下c#背后的IL)


    而spirvcross也是爷爷开发的一个反编译项目,专门把spirv反编译成各种shader源文件

    https://github.com/KhronosGroup/SPIRV-Cross

    官网上说他的功能是,(反编译spirv)生成可读的GLSL,苹果MSL,HLSL,c++,json好了,天下大同了

    • Convert SPIR-V to readable, usable and efficient GLSL
    • Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
    • Convert SPIR-V to readable, usable and efficient HLSL
    • Convert SPIR-V to debuggable C++ [DEPRECATED]
    • Convert SPIR-V to a JSON reflection format [EXPERIMENTAL]


    废话不多说,咱们试试

    实践方案一

    DirectXShaderCompiler 还要自己重编译,麻烦(其实是我没编译通过…build.py写的太烂了,辣鸡微软)

    好在微软直接给了个整合好的方案一

    ShaderConductor

    https://github.com/microsoft/ShaderConductor

    根据文档指导,直接下个最新的预发行版本就好

    https://dev.azure.com/msft-ShaderConductor/public/_build/results?buildId=205&view=artifacts&type=publishedArtifacts

    image

    下份windowsx64的回来,其它平台的我没测试,都是命令行工具,大差不差。

    写一个test.hlsl

    image

    然后执行命令行来编译成glsl

    image

    ShaderConductorCmd –I test.hlsl –E vs_main –S vs –T glsl –V 200

    一长串的参数

    -I test.hlsl 输入文件

    -E vs_main 要编译的函数

    -S vs   编译那种shader

    -T glsl 输出为glsl格式

    -V 110 glsl版本号 ,glsl版本号

    副GLSL版本号表

    2.0 110

    2.1 120

    3.0 130

    3.1 140

    3.2 150

    3.3 330

    4.0 400

    4.1 410

    4.2 420

    4.3 430

    4.5 450


    产生的ios_matal文件

    image

    产生的glsl文件

    image

    问题,因为这个方案里的DXshadercompiler 是dx11的,所以这有个问题

    image

    我单独写的uniform matView也被放进了cbuffer里,观看glsl就会发现有了语义变化,这就像卡了一根刺。


    实验方案二

    下载glsllang

    https://github.com/KhronosGroup/glslang

    有release下载

    https://github.com/KhronosGroup/glslang/releases

    也下载个x64的

    下载spirvcross

    https://github.com/KhronosGroup/SPIRV-Cross

    也有release下载

    https://github.com/KhronosGroup/SPIRV-Cross/releases

    也下载个x64的

    解压出来就能用


    这次写glsl

    image

    glsllang 默认使用文件扩展名识别功能

    vertexshader就要.vert结尾


    image

    调用上述命令编译test.vert 和 test.frag 分别是 vertexshader 和 fragmentshader

    分别得到frag.spv 和 vert.spv文件


    这就是spirv的二进制格式shader


    然后调用spirvcross 可以反编译他们到不同的shader

    image

    没有参数就反编译为glsl

    加--hlsl就反编译为hlsl

    加--msl就反编译为苹果metal

    还有一堆参数就得你自己研究了

    生成的hlsl比较啰嗦

    image

    imageimage

    生成的glsl就比较干爽了

    最后说两句

    目前我想要做的备胎,第一服务对象是Android(gl +vulkan)

    第二才考虑 IOS PC web 这些

    方案二明显更加合适,使用glsl作为基准,对gl和vulkan环境支持良好,在第二考虑时才需要spirvcross上马,可以支持dx 和 metal。


    原理通了,接下去就是整合了。

  • 相关阅读:
    Cassandra内部架构
    Cassandra数据模型
    windows10 docker安装使用
    vue用async、await实现同步请求
    navicat mysql 书写存储过程并导出成sql
    idea svn 文件还原到指定版本
    vscode vue 去掉语法提示
    elasticsearch regexp查询特殊字符处理
    redis中获取不同自增数的方法
    java Elasticsearch 进行嵌套子聚合
  • 原文地址:https://www.cnblogs.com/crazylights/p/13372169.html
Copyright © 2020-2023  润新知