精华内容
下载资源
问答
  • shader 编译
    千次阅读
    2019-09-28 22:33:40

    去掉opengles2.0能省一半时间

    换ssd

     Compiled shader 'Shader Forge/Scenes_Ground_Standard_M' in 315.51s
        gles (total internal programs: 31104, unique: 7880)
        gles3 (total internal programs: 31104, unique: 7880)
    Compressed shader 'Shader Forge/Scenes_Ground_Standard_M' on gles from 25.75MB to 1.39MB
    Compressed shader 'Shader Forge/Scenes_Ground_Standard_M' on gles3 from 31.00MB to 1.15MB

    minggoddess 2018/5/16 14:45:22

    Compiled shader 'Shader Forge/Scenes_Item_Alpha' in 8.35s
        gles (total internal programs: 31680, unique: 8072)
        gles3 (total internal programs: 31680, unique: 8072)
    Compressed shader 'Shader Forge/Scenes_Item_Alpha' on gles from 21.01MB to 1.07MB
    Compressed shader 'Shader Forge/Scenes_Item_Alpha' on gles3 from 26.81MB to 0.95MB
    Compressed shader 'Shader Forge/Scenes_Lobby_Chair' on gles from 0.71MB to 0.01MB 
     
    这两组数据的差异说明  时间不仅仅和variants数量有关
    测下来 大概是这个样子 (total internal programs: 31680, unique: 8072 这个量比较大也没什么
    variants和shader的ab文件大小正相关
    至于编译时间 测下来和variants不是太。。。取决于shader里面的内容
     
    处理Variants用
    shader variant collection
     
     

    转载于:https://www.cnblogs.com/minggoddess/p/9046142.html

    更多相关内容
  • UE4 Shader 编译以及变种实现

    千次阅读 2020-09-17 21:55:20
    这篇文章主要是我对UE4中Shader编译过程以及变种的理解,了解这一块挺有必要的,毕竟动辄几千上万个Shader的编译在UE里简直是家常便饭,了解它底层的实现机制后内心踏实一点,要去修改的话大方向也不错 这部分工作...

    UE4 Shader 编译以及变种实现

    https://zhuanlan.zhihu.com/p/154081604

    一 , 动机

    这篇文章主要是我对UE4中Shader编译过程以及变种的理解,了解这一块挺有必要的,毕竟动辄几千上万个Shader的编译在UE里简直是家常便饭,了解它底层的实现机制后内心踏实一点,要去修改的话大方向也不错

    这部分工作是我之前就做好的,文章里涉及内部修改的地方都被我阉割掉了(阉割版,之后还有内容我再加。。 工作繁忙外加懒)

    所以这篇文章主要用于知识普及,分享给广大被UE4中的Shader编译折磨的码农们,凑活着看把,看完其实应该都了解了,有收获的记得点赞哟。

     

    二 , UE4中Shader的组织和获取

    在讲具体的Shader编译过程时,先讲UE4的渲染过程,渲染过程中是怎么拿Shader的,最后再讲这些Shader是怎么生成的

    虚幻引擎中讲到线程主要有三个:游戏线程,渲染线程,RHI线程。

    其中我们平时关心的比较多的就是游戏线程和渲染线程了,至于RHI线程偏向于底层硬件接口,是甚少关心的,一般情况下也很少有需要改动到RHI线程的东西

    2.1 渲染线程

    虚幻引擎在FEngineLoop::PreInit中对渲染线程进行初始化

    具体的位置是在StartRenderingThread函数里面,此时虚幻引擎主窗口是尚未被绘制出来的,渲染线程的启动位于StartRenderingThread函数里面,这个函数大概做了以下几件事

    1:通过FRunnableThread::Create函数创建渲染线程

     

    2:等待渲染线程准备好从自己的TaskGraph取出任务并执行

     

    3:注册渲染线程

     

    4:创建渲染线程心跳更新线程

     

    2.2 渲染线程的运行

    在ue4的体系中,

    渲染线程的主要执行内容在全局函数RenderingThreadMain(RenderingThread.cpp)中

    从本质上来讲它更像是一个员工,等着老板给他派任务,老板塞给他的任务都会放在TaskMap中,他则负责不断的提取这些任务去执行

    老板可以通过ENQUEUE_RENDER_COMMAND系列宏,给员工派发任务(添加到TaskMap中),下图说明了这个过程

     

    具体代码调用实例如下,这个宏是在游戏线程中调用的,有时候游戏线程中有一些资源发生了变动,或者添加了一些新的资源,抑或是因为一些逻辑而要去改到渲染线程的一些操作,都需要有一种方法去通知到渲染线程,就像是两艘并行飞驰的船,各自走自己的路,另一艘船上发生了什么是完全不知道的,而UE4就通过设置一系列宏为两艘船之间的通信提供了方法

    em。。 马赛克忽略把

    员工执行任务时也不是直接向GPU发送指令,而是将渲染命令添加到RHICommandList,也就是RHI命令列表中,由RHI线程不断取出指令,向GPU发送,并阻塞等待结果

     

    此时RHI线程虽然阻塞,但是渲染线程依然正常工作,可以继续处理向RHI命令列表填充指令

     

    2.3 渲染过程中Shader的来源及选择

    明白了上述那些概念我们知道,屏幕结果就像是我们最终要做出来的产品,老板就像是产品经理,告诉员工这个产品要怎么做,并交给员工对应的资源,员工根据这些资源,和老板的命令去完成最终的产品(绘制到屏幕上)

    首先讲这些资源在ue4中对应的是什么,以及员工在完成不同的工作阶段(绘制Pass)时是如何从这么多资源中拿到自己想要的资源的,再去讲这些资源的生成

     

    资源的组织:ShaderMap

    那么屏幕上的画面究竟是如何呈现的呢?员工是怎么样去用这些资源的呢,换句话说就是老板给员工的资源,员工是怎么处理成最终能用的资源的?并且这些资源是怎么组织的?

    这里就涉及到一个名词:ShaderMap

    用过虚幻4的渲染的都知道,虚幻引擎中的着色器数量是非常庞大的,如果改动一个材质,经常就需要编几千个甚至上万个Shader,其实也就是说单个材质会编译出多个Shader,这一点是非常重要的

    用一个简单点的概念来理解ShaderMap,可以把它理解成一个三维矩阵,长度为每个材质类型,宽度为每个渲染阶段,高度为每个顶点工厂类型,矩阵的每一个方格都对应了一组着色器组合(顶点着色器,像素着色器),材质也不一定参与全部阶段,所以这个三维矩阵中是存在有很多空缺的

    顶点工厂在ue4中的含义是负责抽象顶点数据以供后面的着色器获取,从而让着色器能够忽略由于顶点类型造成的差异,比如说普通的静态网格物体和使用GPU进行蒙皮的物体,二者的顶点数据不同,但是通过顶点工厂进行抽象后,提供统一的数据获取接口,供后面的着色器使用

     

    资源的选择:怎么从ShaderMap中拿到想要的Shader

    现在是第二个问题,如何根据当前阶段,当前的材质类型,当前顶点工厂类型,从这个三维矩阵中获得需要的着色器组合呢

    以一个StaticMesh物体的渲染为例(动态物体不同),对着色器数据选择的过程如下:

    1:渲染线程把这个物体添加进场景 AddToScene

     

    2:更新场景的静态物体绘制列表 AddStaticMeshes

     

    3: 调用CacheMeshDrawCommands,开始生成当前物体的绘制命令MeshDrawCommands并缓存住

     

    4:遍历所有的Rendering Pass类型,获取当前场景的CachedDrawLists生成Drawlistcontext

     

    5:调用不同Pass(以BasePass为例)的AddMeshBatch函数,并将Drawlistcontext作为参数传入(方便之后把生成的绘制命令缓存住)

     

    6:通过一系列参数判断该Mesh应不应该在当前Pass(BasePass为例)生成绘制命令,如果验证通过,那么调用当前Pass的Process函数

    其实也没啥,但是还是加马赛克

     

    7:获取该Mesh在当前Pass绘制需要的Shaders,绘制状态,光栅化状态,并最终生成该Mesh的绘制命令

     

     

     

    所以到这一步就讲清楚了渲染时怎么去拿Shader的流程,需要去看不同Pass的GetShaders函数,结合之前对ShaderMap的分析来看它的传入参数,MaterialResource对应它使用的材质资源,VertexFactory的type对应所用到的顶点工厂类型,最后还有用到的顶点和像素着色器

    最终得到顶点着色器和像素着色器的调用如下(此时材质类型和渲染Pass已经确定)

     

     

    材质的GetShader函数首先以当前顶点工厂类型的id为索引,通过GetMeshShaderMap函数从OrderedMeshShaderMaps成员变量中查询到对应顶点工厂类型的MeshShaderMap,随后调用当前MeshShaderMap的GetShader函数,以当前着色器类型为参数查询,查询到实际对应的着色器

     

    总结如下:实质上获取一组着色器组合需要的三个变量:渲染Pass,顶点工厂类型,材质类型,这也就不难理解UE4中对资源的组织形式了

     

    三 , UE4中Shader的生成

    MaterialShader的编译

    在第二部分的内容中已经说清楚了ue4中Shader的组织形式以及具体是怎么去获取,那么接下来的问题就是如何去生成这些Shader,及材质如何编译,产生ShaderMap并缓存起来

    在之前一篇对材质分析的文章中已经说到当HLSL代码生成后(这篇文章在我的笔记里,之后考虑放出来),就需要进入到真正的着色器编译阶段

    材质节点图生成的HLSL代码只是一批函数,并不具备完整的着色器信息,这些代码会镶嵌到真正的着色器编译环境中(FShaderCompilerEnvironment),重新编译成最终的ShaderMap中每一个着色器,主要流程如下

    1:保存材质并编译当前材质,触发Shader编译,调用FMaterial::BeginCompileShaderMap()

    2:新建一个ShaderMap实例,调用HLSLTranslator把材质节点翻译成HLSL代码

     

    3:初始化着色器编译环境,FShaderCompilerEnvironment通过MaterialTraslator::GetMaterialEnvironment初始化实例,主要就是去设置宏

    3.1:根据当前Material的各种属性,初始化各种着色器宏定义,从而控制编译过程中的各种宏开关是否启动

     

    3.2:根据FHLSLMaterialTranslator在解析过程中得出当前的参数集合,添加参数定义到环境中

     

    4:开始实际的编译工作

    4.1:调用NewShaderMap的Compile函数:

    a,调用FMaterial::SetupMaterialEnvironment函数,设置当前的编译环境,这里面也会去设置各种宏定义

     

    b,获取所有顶点工厂类型,对于每一种顶点工厂类型,查看该类型对应的ShaderMap是不是已经被使用,如果被使用就去BeginCompile

     

    c,BeginCompile函数中会去遍历所有的ShaderType,中间会调到实例类的ModifyCompilationEnvironment,最终调用全局函数GlobalBeginCompileShader,这个全局函数会去填充FShaderCompileJob,包括设置shader格式、usf路径、注入宏等等

     

    d,真正执行编译任务的是把所有FShaderCompileJob交给FShaderCompilingManager,并且让其马上执行编译并返回

     

    如何实现Shader变种?

    FMeshMaterialShaderType继承自FShaderType,他存有模板类的两个静态函数指针:ModifyCompilationEnvironment和ShouldCompilePermutation,因此每次遍历我们都可以访问到这两个函数

    上文中的c阶段会先调用ShouldCompilePermutation询问TMobileBasePassPS是否为当前Template、VertexFactory、Material组合编译Shader

    如果需要编译,则调用ModifyCompilationEnvironment注入该当前模板确定的宏,以此实现Shader的变种。

     

    GlobalShader的编译

    在使用编辑器的时候,经常会有需要改动到Shader文件,并且需要在编辑器中查看效果的需求,与材质编辑器中的材质Shader不一样,材质编辑器提供了编译按钮,对材质的改动都可以保存并编译出Shader保存到ShaderMap中,所以如果改动了目录下的Shader文件怎么告诉引擎去帮我们编译修改后的Shader

    虚幻针对这个功能已经提供了相应的指令

    recompileshaders changed ,recompileshaders global,recompileshaders material <MaterialName>,recompileshaders all,recompileshaders <path>

    如果不知道这些指令,一个比较死的办法自然是重启编辑器,让它重编改动过的Shader,当然也可以不重启编辑器来重编这些改动过的shader,比如使用 recompileshaders changed,这里首先讲通过指令重编的方法,它的具体流程是怎样?

     

    一:动态重编Shader 不需要重开编辑器

    1: 修改Shader文件,保存,在控制台输入 recompileshaders changed

     

    2:调用RecompileShaders,根据指令的内容进入不同的分支,先去匹配具体的命令内容

     

    3:寻找过期的Shader文件(改动过的Shader)

     

    4:如果当前对Shader文件(.usf)没有任何改动,直接返回No Shader changes found,如果有改动,调用BeginRecompileGlobalShaders

    a,调用FlushRenderingCommands,等待渲染线程执行完所有挂起的渲染命令

    b,根据当前平台得到GlobalShaderMap,GetGlobalShaderMap(ShaderPlatform),这里也可以看出来不同的ShaderType是存在不同的ShaderMap中的

    c,从ShaderMap中移除过期的CurrentGlobalShaderType和ShaderPipline(顶点还是像素着色器等等..)的Shader

    d,调用VerifyGlobalShaders重编ShaderMap中的Shader

     

    5:完成GlobalShader的重编,调用FinishRecompileGlobalShaders(),该函数会阻塞直到所有的Global Shaders被编译和处理完毕

     

    二:重开编辑器

    1:在引擎的preinit函数中调用CompileGlobalShaderMap

    2:新建一个GlobalShaderMap实例

    3:查看Shader缓存DDC中的内容与设定的KeyString是否一致,如果不一致说明缓存中对应部分的内容已经失效了,UE就会去重编这部分内容(对应最开始说到的重编Shader问题),并且去重新生成这部分的DDC

     

    4:从DDC中反序列化出来GlobalShaderMap实例的内容

     

    5:接下来就是一些Shader资源的初始化操作...

     

    三 , UE4中材质Cook保存的是什么

    所谓的Cook是指把平台无关的编辑向数据转化为特定平台运行时所需的数据,对于材质来说就是把上述的usf文件和材质连线编译成安卓运行时需要的GLSL源码。

    1:Cook Commandlet会首先调用一个Package里面所有的UObject的BeginCacheForCookedPlatformData(const ITargetPlatform *TargetPlatform)方法,该方法由各个UObject派生类各自实现,目的是生成特定所需数据并缓存下来,对于材质来讲就是UMaterial的BeginCacheForCookedPlatformData

     

    a,开始为目标平台缓存着色器,并将正在编译的材质资源存储到CachedMaterialResourcesForCooking中

     

    b,为当前ShaderFormat/FeatureLevel、QualityLevel生成一个FMaterialResource数组,并调用CacheShadersForResources填充其内容

     

    2:之后Cook Commandlet会保存该Package,也就是是去执行到UMaterial里面的Serialize方法

    实际上前面部分提到的usf文件和材质连线都通过CacheShadersForResources被转化成了一个个FMaterialResource,所以FMaterialResource到底是什么东西?

    在UMaterial能找到如下成员

    结合之前的分析,不难得出 UMaterial持有 QualityLevelNum * FeatureLevelNum 个FMaterialResource,可以通过QualityLevel和FeatureLevel索引到FMaterialResource

    FMaterialResource里有一个关键的成员FMaterialShaderMap,FMaterialShaderMap可以通过FVertexFactoryType::GetId()来索引到FMeshMaterialShaderMap;而FMeshMaterialShaderMap可以通过FShaderType来索引FShader

    因此FMaterialResource里面存放的实际上是FShader的集合,而FShader里面存放的就是最终使用的Shader代码了

     

     

     

     

     

     

    编辑于 07-09

     

     

     

     

     

    展开全文
  • Vulkan shader编译

    2020-04-09 12:11:44
    大家好,接下来将为大家介绍Vulkan shader编译。 一、编译shader 在项目根目录下创建一个子目录,名shaders用于存储顶点着色器文件shader.vert和片段着色器文件shader.frag。GLSL着色器官方没有约定的扩展名,但是...

    大家好,接下来将为大家介绍Vulkan shader编译。

    一、编译shader

    在项目根目录下创建一个子目录,名shaders用于存储顶点着色器文件shader.vert和片段着色器文件shader.frag。GLSL着色器官方没有约定的扩展名,但是这两个扩展名是比较普遍通用的。

    shader.vert内容如下:

    #version 450
    #extension GL_ARB_separate_shader_objects : enable
    
    out gl_PerVertex {
        vec4 gl_Position;
    };
    
    layout(location = 0) out vec3 fragColor;
    
    vec2 positions[3] = vec2[](
        vec2(0.0, -0.5),
        vec2(0.5, 0.5),
        vec2(-0.5, 0.5)
    );
    
    vec3 colors[3] = vec3[](
        vec3(1.0, 0.0, 0.0),
        vec3(0.0, 1.0, 0.0),
        vec3(0.0, 0.0, 1.0)
    );
    
    void main() {
        gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
        fragColor = colors[gl_VertexIndex];
    }

    shader.frag文件内容如下:

    #version 450
    #extension GL_ARB_separate_shader_objects : enable
    
    layout(location = 0) in vec3 fragColor;
    
    layout(location = 0) out vec4 outColor;
    
    void main() {
        outColor = vec4(fragColor, 1.0);
    }

    现在我们尝试使用glslangValidator程序编译SPIR-V二进制码。

    Windows

    创建一个compile.bat批处理文件,内容如下:

    C:/VulkanSDK/1.0.17.0/Bin32/glslangValidator.exe -V shader.vert
    C:/VulkanSDK/1.0.17.0/Bin32/glslangValidator.exe -V shader.frag
    pause

     

    glslangValidator.exe的path路径替换为你的VulkanSDK安装路径,然后双击该文件运行。

    End of platform-specific instructions

    这两个命令使用-V标志调用编译器,该标志告诉它将GLSL源文件编译为SPIR-V字节码。运行编译脚本时,会看到创建了两个SPIR-V二进制文件:vert.spvfrag.spv。这些名称从着色器中派生而来,但是可以重命名为任何名字。在编译着色器时,可能收到关于某些功能缺失的警告信息,在这里放心的忽略它们。

    如果着色器包含语法错误,那么编译器会按照您的预期告诉具体的行号和问题。尝试省略一个分号,然后重新运行编译脚本。还可以尝试运行编译器,而无需任何参数来查看它支持哪些类型的标志。例如,它可以将字节码输出为可读的格式,以便准确了解着色器正在执行的操作以及在此阶段应用的任何优化。

     

    二、加载shader

    现在我们有一种产生SPIR-V着色器的方法,是时候加载它们到我们的程序中,以便在适当的时候插入到图形管线中。首先我们编写一个辅助函数用以加载二进制数据文件。

    #include <fstream>
    
    ...
    
    static std::vector<char> readFile(const std::string& filename) {
        std::ifstream file(filename, std::ios::ate | std::ios::binary);
    
        if (!file.is_open()) {
            throw std::runtime_error("failed to open file!");
        }
    }

    readFile函数将会从文件中读取所有的二进制数据,并用std::vector字节集合管理。我们使用两个标志用以打开文件:

    • ate:在文件末尾开始读取
    • binary:以二进制格式去读文件(避免字符格式的转义)

    从文件末尾开始读取的优点是我们可以使用读取位置来确定文件的大小并分配缓冲区:

    size_t fileSize = (size_t) file.tellg();
    std::vector<char> buffer(fileSize);

    之后我们可以追溯到文件的开头,同时读取所有的字节:

    file.seekg(0);
    file.read(buffer.data(), fileSize);

    最后关闭文件,返回字节数据:

    file.close();
    
    return buffer;

    我们调用函数createGraphicsPipeline加载两个着色器的二进制码:

    void createGraphicsPipeline() {
        auto vertShaderCode = readFile("shaders/vert.spv");
        auto fragShaderCode = readFile("shaders/frag.spv");
    }

    确保着色器正确加载,并打印缓冲区的大小是否与文件实际大小一致。

     

     

     

     

     

     

     

     

     

    展开全文
  • 文章目录What is shader compilation jank? -什么是shaders编译卡顿?What do we mean by “first run”? - 我们所说的“第一次运行”是什么意思?How to use SkSL warmup - 如何使用 SkSL 热身Frequently asked ...


    If the animations on your mobile app appear to be janky, but only on the first run, you can warm up the shader captured in the Skia Shader Language (SkSL) for a significant improvement.
    如果你的手机 App上的动画看起来很卡顿,但只是在第一次运行时,你可以预热在 Skia shaders语言 (SkSL) 中捕获的shaders,以此获得显着的改进。
    在这里插入图片描述
    Side-by-side screenshots of janky mobile app next to non-janky app
    卡顿App与非卡顿App并排的屏幕截图

    What is shader compilation jank? -什么是shaders编译卡顿?

    If an app has janky animations during the first run, and later becomes smooth for the same animation, then it’s very likely due to shader compilation jank.
    如果一个App在第一次运行时出现了animation卡顿,后来相同的animation却变得流畅,那么很可能是shaders编译 导致的卡顿。

    More technically, a shader is a piece of code that runs on a GPU (graphics processing unit). When a shader is first used, it needs to be compiled on the device. The compilation could cost up to a few hundred milliseconds whereas a smooth frame needs to be drawn within 16 milliseconds for a 60 fps (frame-per-second) display.
    从技术上讲,shaders是在 GPU(图形处理单元)上运行的一段代码。 首次使用shaders时,需要在设备上对其进行编译。 编译可能会花费数百毫秒,而流畅的显示帧需要在 16 毫秒内绘制,才能实现 60 fps(每秒帧数)的显示。

    Therefore, a compilation could cause tens of frames to be missed, and drop the fps from 60 to 6. This is compilation jank. After the compilation is complete, the animation should be smooth.
    因此,一次编译可能会导致数十帧丢失,并将 fps 从 60 降至 6。这就是编译卡顿。 在编译完成后,animation应该是流畅运行的。

    Definitive evidence for the presence of shader compilation jank is to see GrGLProgramBuilder::finalize in the tracing with --trace-skia enabled. See the following screenshot for an example timeline tracing.
    存在shaders编译卡顿的明确现象是在启用了 --trace-skia 的跟踪中看到 GrGLProgramBuilder::finalize。 有关时间线跟踪的示例,请参见下面的屏幕截图。
    在这里插入图片描述
    A tracing screenshot verifying jank
    排查卡顿的跟踪屏幕截图

    What do we mean by “first run”? - 我们所说的“第一次运行”是什么意思?

    On Android, “first run” means that the user might see jank the first time opening the app after a fresh installation. Subsequent runs should be fine.
    在 Android 上,“首次运行”意味着用户在全新安装后第一次打开App时可能会看到卡顿。 后续运行就没问题。

    On iOS, “first run” means that the user might see jank when an animation first occurs every time the user opens the app from scratch.
    在 iOS 上,“首次运行”意味着用户可能会在每次用户从头开始打开App时第一次出现动画时看到卡顿。

    How to use SkSL warmup - 如何使用 SkSL 热身

    As of release 1.20, Flutter provides command line tools for app developers to collect shaders that might be needed for end-users in the SkSL (Skia Shader Language) format. The SkSL shaders can then be packaged into the app, and get warmed up (pre-compiled) when an end-user first opens the app, thereby reducing the compilation jank in later animations. Use the following instructions to collect and package the SkSL shaders:
    从 1.20 版开始,Flutter 为App开发人员提供命令行工具,以收集最终用户可能需要的 SkSL(Skia shaders语言)格式的shaders。SkSL shaders可以打包到App中,并在最终用户首次打开App时进行预热(预编译),从而减少后续animation的编译卡顿。 使用以下指令收集和打包 SkSL shaders:

    1.Run the app with --cache-sksl turned on to capture shaders in SkSL:
    1.运行App带上 --cache-sksl 参数,以便在 SkSL 中捕获shaders:

    flutter run --profile --cache-sksl
    

    If the same app has been previously run without --cache-sksl, then the --purge-persistent-cache flag may be needed:
    如果之前在没有 --cache-sksl 的情况下运行相同的App,则可能需要 --purge-persistent-cache 标志:

    flutter run --profile --cache-sksl --purge-persistent-cache
    

    This flag removes older non-SkSL shader caches that could interfere with SkSL shader capturing. It also purges the SkSL shaders so use it only on the first --cache-sksl run.
    此标志会消除 ”较旧的非 SkSL shaders缓存“ 对 ”SkSL shaders捕获“的干扰。 它还会清除 SkSL shaders,所以只在第一次运行 --cache-sksl 时使用它。

    2.Play with the app to trigger as many animations as needed; particularly those with compilation jank.
    2.运行App以根据需要触发尽可能多的animation; 特别是那些有编译卡顿的。

    3.Press M at the command line of flutter run to write the captured SkSL shaders into a file named something like flutter_01.sksl.json. For best results, capture SkSL shaders on actual Android and iOS devices separately.
    3.在 flutter run 的命令行按 M 将捕获的 SkSL shaders写入名为 flutter_01.sksl.json 的文件中。 为了获取到最佳效果,请分别在真实的 Android 和 iOS 手机上捕获 SkSL shaders。

    Build the app with SkSL warm-up using the following, as appropriate:
    适当的通过以下方法 让 编译的 App带上 ”SkSL 预热“:

    Android:

    flutter build apk --bundle-sksl-path flutter_01.sksl.json
    

    or 或者

    flutter build appbundle --bundle-sksl-path flutter_01.sksl.json
    

    iOS:

    flutter build ios --bundle-sksl-path flutter_01.sksl.json
    

    If it’s built for a driver test like test_driver/app.dart, make sure to also specify --target=test_driver/app.dart (e.g., flutter build ios --bundle-sksl-path flutter_01.sksl.json --target=test_driver/app.dart).
    如果它是为像 test_driver/app.dart 这样的驱动程序测试而构建的,请确保还指定 --target=test_driver/app.dart (例如,flutter build ios --bundle-sksl-path flutter_01.sksl.json --target= test_driver/app.dart)。

    5.Test the newly built app.
    5.测试新建的App。

    Alternatively, you can write some integration tests to automate the first three steps using a single command. For example:
    或者,你可以编写一些集成测试以使用单个命令自动执行前三个步骤。 例如:

    flutter drive --profile --cache-sksl --write-sksl-on-exit flutter_01.sksl.json -t test_driver/app.dart
    

    With such integration tests, you can easily and reliably get the new SkSLs when the app code changes, or when Flutter upgrades. Such tests can also be used to verify the performance change before and after the SkSL warm-up. Even better, you can put those tests into a CI (continuous integration) system so the SkSLs are generated and tested automatically over the lifetime of an app.
    通过此类集成测试,你可以在app代码更改或 Flutter 升级时轻松可靠地获取新的 SkSL。 此类测试还可用于验证 SkSL 预热前后的性能变化。 更好的是,你可以将这些测试放入 CI(持续集成)系统中,以便在App的整个生命周期内自动生成和测试 SkSL。

    Note: The integration_test package is now the recommended way to write integration tests. See the Integration testing page for details.
    注意: integration_test 包现在是编写集成测试的推荐方式。 有关详细信息,请参阅集成测试页面

    Take the original version of Flutter Gallery as an example. The CI system is set up to generate SkSLs for every Flutter commit, and verifies the performance, in the transitions_perf_test.dart test. For more details, see the flutter_gallery_sksl_warmup__transition_perf and flutter_gallery_sksl_warmup__transition_perf_e2e_ios32 tasks.
    以原版 Flutter Gallery 为例。 CI 系统设置为为每次 Flutter 提交生成 SkSL,并在 transitions_perf_test.dart 测试中验证性能。 有关更多详细信息,请参阅 flutter_gallery_sksl_warmup__transition_perfflutter_gallery_sksl_warmup__transition_perf_e2e_ios32 任务。

    The worst frame rasterization time is a nice metric from such integration tests to indicate the severity of shader compilation jank. For instance, the steps above reduce Flutter gallery’s shader compilation jank and speeds up its worst frame rasterization time on a Moto G4 from ~90 ms to ~40 ms. On iPhone 4s, it’s reduced from ~300 ms to ~80 ms. That leads to the visual difference as illustrated in the beginning of this article.
    最差帧raster时间是此类集成测试的一个很好的指标,用于指示shaders编译卡顿的严重性。 例如,上述步骤减少了 Flutter 库的shaders编译卡顿,并将其在 Moto G4 上的最差raster时间从 ~90 ms 加速到 ~40 ms。 在 iPhone 4s 上,它从 ~300 ms 减少到 ~80 ms。 这导致了本文开头所示的视觉差异。

    Frequently asked questions- 常问的问题

    Why not just compile or warm up all possible shaders? - 为什么不直接编译或预热所有可能的shaders?

    If there were only a limited number of possible shaders, then Flutter could compile all of them when an application is built. However, for the best overall performance, the Skia GPU backend used by Flutter dynamically generates shaders based on many parameters at runtime (for example draws, device models, and driver versions). Due to all possible combinations of those parameters, the number of possible shaders multiplies quickly. In short, Flutter uses programs (app, Flutter, and Skia code) to generate some other programs (shaders).
    如果shaders数量有上限,那么 Flutter 可以在构建App时编译所有shaders。 然而,为了获得最佳的整体性能,Flutter 使用的 Skia GPU 在背后会在运行时根据许多参数(例如绘图、设备模型和驱动程序版本)动态生成shaders。 由于这些参数的所有可能组合,可能的shaders数量迅速增加。 简而言之,Flutter 使用程序(app、Flutter 和 Skia 代码)来生成其他一些程序(shaders)。
    The number of possible shader programs that Flutter can generate is too large to precompute and bundle with an application.
    Flutter 可以生成的可能shaders程序的数量太大而无法预先计算并与App捆绑在一起。

    Can SkSLs captured from one device help shader compilation jank on another device? -从一台设备捕获的 SkSL 能否帮助shaders编译在另一台设备上卡顿?

    Theoretically, there’s no guarantee that the SkSLs from one device would help on another device (but they also won’t cause any troubles if SkSLs aren’t compatible across devices). Practically, as shown in the table on this SkSL-based warmup issue, SkSLs work surprisingly well even if 1) SkSLs are captured from iOS and then applied to Android devices, or 2) SkSLs are captured from emulators and then applied to real mobile devices. As the Flutter team has only a limited number of devices in the lab, we currently don’t have enough data to provide a big picture of cross-device effectiveness. We’d love you to provide us more data points to see how it works in the wild—FrameTiming can be used to compute the worst frame rasterization time in release mode; the worst frame rasterization time is a good indicator on how severe the shader compilation jank is.
    从理论上讲,不能保证来自一台设备的 SkSL 会在另一台设备上有所帮助(但如果 SkSL 不能跨设备兼容,它们也不会造成任何问题)。 实际上,如这个基于 SkSL 的预热问题的表格所示,即使 1) 从 iOS 捕获 SkSL,然后将其应用于 Android 设备,或者 2) 从模拟器捕获 SkSL,然后将其应用于真实的移动设备,SkSL 的工作效果也出奇地好 . 由于 Flutter 团队在实验室中只有有限数量的设备,我们目前没有足够的数据来提供跨设备有效性的大图。 我们希望你提供更多数据点,看看它在实验室之外是如何工作的——FrameTiming 可用于计算release模式下最差的raster化时间; 最差帧raster时间可以很好地指示shaders编译卡顿的严重程度。

    Why can’t you create a single “ubershader” and just compile that once? -为什么你不能创建一个单一的“ubershader”并且只编译一次呢?

    One idea that people sometimes suggest is to create a single large shader that implements all of Skia’s features, and use that shader while the more optimized bespoke shaders are being compiled.
    人们有时建议的一个想法是创建一个实现 Skia 所有功能的大型shaders,并在编译更优化的定制shaders时使用该shaders。

    This is similar to a solution used by the Dolphin Emulator.
    这类似于 Dolphin Emulator 使用的解决方案。

    In practice we believe implementing this for Flutter (or more specifically for Skia) would be impractical. Such a shader would be fantastically large, essentially reimplementing all of Skia on the GPU. This would itself take a long time to compile, thus introducing more jank; it would not necessarily be fast enough to avoid jank even when compiled; and it would likely introduce fidelity issues (e.g. flickering) since there would likely be differences in precise rendering between the optimized shaders and the “ubershader”.
    在实践中,我们认为为 Flutter(或更具体地为 Skia)实现这一点是不切实际的。 这样的shaders会非常大,本质上是在 GPU 上重新实现所有 Skia。 这本身会花费很长时间来编译,从而引入更多的卡顿问题; 即使在编译时,它也不一定足够快以避免卡顿; 并且它可能会引入保真度问题(例如闪烁),因为优化shaders和“ubershader”之间的精确渲染可能存在差异。

    That said, Flutter and Skia are open source and we are eager to see proofs-of-concept along these lines if this is something that interests you. To get started, please see our contribution guidelines.
    也就是说,Flutter 和 Skia 是开源的,如果你对此感兴趣,我们渴望看到这些方面的概念验证。 要开始使用,请参阅我们的贡献指南

    This process would be easier if the flutter tool could do X! - 这个过程会更轻松,如果flutter工具可以做 X!

    There are a number of possible ways that the tooling around shader warm-up could be improved. Some are already listed as ideas under our Early-onset jank project on GitHub. Please let us know what is important to you by giving a thumbs-up to your feature request, or by filing a new one if one doesn’t already exist.
    有许多可能的方法可以改进围绕shaders预热的工具。 有些已经被列为我们在 GitHub 上的 Early-onset jank 项目下的想法。 对你关注的feature request给予一个thumbs-up,或者创建新的feature request(如果该feature还不存在),以此来让我们知道什么对你很重要。

    Future work - 未来的工作

    On both Android and iOS, shader warm-up has a few drawbacks:
    在 Android 和 iOS 上,shaders预热都有一些缺点:

    1. The size of the deployed app is larger because it contains the bundled shaders.
      发布的App的包体积会更大,因为它包含捆绑的shaders。
    2. App startup latency is longer because the bundled shaders need to be precompiled.
      App启动时间会较长,因为捆绑的shaders需要预编译。
    3. Most importantly, we are not happy with the developer experience of shader warm-up. In particular we view the process of performing training runs, and reasoning about the trade-offs imposed by (1) and (2) to be too onerous.
      最重要的是,我们对shaders预热的开发者体验并不满意。 特别是,我们认为执行训练运行的过程以及对 (1) 和 (2) 强加的权衡进行推理过于繁琐。

    Therefore, we are continuing to investigate approaches to shader compilation jank, and jank more generally, that do not rely on shader warm-up. In particular, we are both working with Skia to reduce the number of shaders it generates in response to Flutter’s requests, as well as investigating how much of Flutter could be implemented with a small set of statically defined shaders that we could bundle with the Flutter Engine. Stay tuned for more progress!
    因此,我们将继续研究不依赖shaders预热的shaders编译卡顿和更普遍的卡顿的解决方法。 特别是,我们都在与 Skia 合作,以减少它为响应 Flutter 的请求而生成的shaders数量,并研究可以使用一组静态定义的shaders来实现多少 Flutter功能,我们可以将这些shaders与 Flutter 引擎捆绑在一起 . 请继续关注以获得更多进展!

    If you have questions on SkSL shader warm-up, please comment on Issue 60313 and Issue 53607. If you have general shader warm-up questions, please refer to Issue 32170.
    如果你对 SkSL shaders预热有任何疑问,请在Issue 60313 和Issue 53607 中发表评论。如果你有一般的shaders预热问题,请参阅Issue 32170

    展开全文
  • Shader编译和链接是将编写好的着色器代码经过一系列封装并参与渲染流水线的过程,使其呈现我们想要的屏幕效果。 Shader编译和链接过程如下图: 实现 1. 创建Program GLuint m_pShaderProgram; bool Shader...
  • 跨平台shader 编译

    千次阅读 2017-04-06 13:16:31
    (本文根据我博客上的文章跨平台shader编译的过去、现在和未来改写。知乎编辑器不支持多个级别的标题,以至于我只能用加粗不加粗来区分了。。。) 很多跨平台游戏引擎都有统一shader的需求。比如KlayGE从建立伊始...
  • UE4 Shader编译以及变种实现

    千次阅读 2020-08-07 18:06:57
    这篇文章主要是我对UE4中Shader编译过程以及变种的理解,了解这一块还是挺有必要的,毕竟动辄几千上万个Shader的编译在UE里简直是家常便饭。了解它底层的实现机制后内心踏实一点,如果要去修改,大方向也不会错。 ...
  • Unity shader 编译指令

    2017-05-28 19:00:31
    在程序片段被编译之前需要个程序加上预编译(#pragma)。一、顶点着色器和片段着色器的编译指令1、#pragma vertex name:编译name函数为顶点着色器 2、#pragma fragment name:编译name函数为片段着色器 3、#pragma ...
  • 关于Unity 5.x Lightmap Shader 编译过慢的分析 缘起 最近在研究Unity 5.x 的 Lightmapping 与 场景打包的相关的知识。发现坑深啊。关于怎么打包怎么用网上的教程太多了,就不再鳌述,在最后Lightmap和Scene可以...
  • 又被Unity坑了一把,简单说下吧,下面都是流水账,结论就写在最后了,就是Unity5 - 5.2的shader编译机制真是不咋地。1.Why Always me?问题是这样的,我照着Unity5 的Standard shader写了一个给我们工程用的简化版的...
  • 编译shader

    2019-08-19 18:21:15
    编译shader 编译shader 根据shader的种类,来创建一个shader的对象 获取shader对应的代码 用显卡驱动编译shader 编译错误的处理 GLuint CompileShader(GLenum shaderType, const char* shaderCode) { GLuint ...
  • Unity的Shader加载编译优化

    千次阅读 2019-05-23 20:47:13
    参考官方关于Shader...最近项目中引入了ShaderVariant机制,将部分shader的变体放到了variant中,但是在加载variant执行warmUp的时候发现卡的时间特别长,连接真机profiler看到如下 之前看到过文章,在Un...
  • 查看你的错误是否跟我一样: 第一种:shader路径不对,windows下的路径分隔符应多加一个\。比如 E:\zhanghongyan\study应该改为E:\\zhanghongyan\\study。第二种,文件找到了但是文件格式不对。 将写的shader文件用...
  • 本教程“授人以渔”,为大家带来零起点的WebGL Shader教学,从图形硬件的发展史开始,讲GPU可编程管线,讲3D模型数据结构、贴图、光照、渲染,让大家能从一个纵深的过程中宏观的了解这种技术的前因后果。教程以Laya...
  • 聊聊引擎底层如何编译Shader脚本

    千次阅读 2018-12-15 16:51:21
    再看看CreateShader函数的实现,我们把Shader编译后,要把Shader中顶点,片段,几何分离一下,至少让GPU知道如何执行。实现代码如下所示: 调用的也是DX提供的接口,讲到这里还没有完结,我们加载Shader的目的是...
  • Shader编译解决方案

    2021-06-16 12:17:46
    } Laya.ShaderPass -> withCompile(compileDefine) { if (Shader3D.debugMode)//开启debug编译shader时生成打印shader参数 this._addDebugShaderVariantCollection(compileDefine); } debugShader : Laya....
  • Unity Shader编译指令

    千次阅读 2019-01-10 00:26:58
    一、、顶点着色器和片段着色器的编译指令 我们在unity中最常见的就是下面前两种,使用就不必介绍了,这里会针对其它一些较为常用的编译指令做一下详细介绍。 1、#pragma vertex name:编译name函数为顶点着色器  2...
  • Shader 这一章节的代码文件是11-...把GLSL Shader 编译成 SPIR-V 对 Vulkan 来说,低级的 shader 代码表现为 SPIR-V。示例程序通过调用一个实用函数把用GLSL写的 shader 程序编译成 SPIR-V: GLSLtoSPV(VK_SHA.
  • GLSL中对Shader编译、链接、使用流程: #创建编写shader程序 顶点着色器程序: //文件名:shaderv.vsh 后面会使用 attribute vec4 position; attribute vec2 textureCoor; varying lowp vec2 varyTextCoor; void...
  • Laya shader编译 解决粒子特效卡顿 使用unity导入粒子特效,在Laya中第一次播放会出现卡顿现象,查了下相关资料发现是特效的shader没有进行预编译导致的,根据Laya官网实现如下代码 使用unity导入粒子特效,在Laya...
  • Shader Model 3.0着色器反编译为HLSL代码 用法 HlslDecompiler [--ast] shader.fxc 程序将在shader.asm中输出程序集列表,例如 ps_3_0 def c0, 1, 0, 2, 0 dcl_texcoord v0.xz mov oC0.x, -v0.z_abs mad oC0.yzw,...
  • Unity3D Shader加载时机和预编译 https://www.cnblogs.com/rexzhao/p/7884905.html 一、ShaderShader Variants 着色器(Shader)是在GPU上执行的小程序,通常情况下,我们自己写的一个着色器文件(xxx.shader)...
  • 报错信息 GLSL compilation failed: 0(21) : error C7528: OpenGL reserves names containing '__' 双击报错VS自动打开VS, 但并未定位到错误代码所在...经检查报错的代码在shader的 cginc文件中,改好即可解...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,218
精华内容 6,487
关键字:

shader 编译