type
status
date
slug
summary
tags
category
icon
password

本篇为最坑的部分,关于shader的导出

 
官方文档相关演示内容参见
关于Shader导出的方式,官方文档里给出了一种写法
这个方案确实是可以正确导出shader的,不过是完全原版,也就是在Renderdoc内对某一个阶段的shader点view后打开的Disassembly界面中Disassembly Type选择默认的那个版本
notion image
这个“默认”来源于上面这段code中的target[0]
如果你希望得到其他版本。理论上按照可以看到的顺序选择不同target序号进行disassmble即可。
但实际上如果你输出所有targets的内容,会发现,数量对不上,即部分Disassmbly Type不会出现在GetDisassemblyTargets中。这是因为有部分是通过第三方插件完成的。
通过第三方插件完成的主要是Spirv相关的几种选项。它们的设置可以在Renderdoc中查看Settings → Shader Viewer
 
比如,上述截图中GLSL(SPIRV-Cross)版本是通过调用SPIRV-Cross.exe这个外部工具实现的,其路径可以在Shader Viewer设置中找到
notion image
 

确认方案

如果你希望获得GLSL(SPIRV-Cross)的结果,就需要在Python中调用SPIRV-Cross。官方文档中表明qrenderdoc库提供了一个类叫ShaderProcessingTool
查看该类的参数可以发现其内容和上述截图中的内容几乎匹配,其中也存在ShaderProcessingTool.CompileShader()和ShaderProcessingTool.DisassembleShader()两个函数。
但是文档中可以看到,其传入的参数必须有一个QWidget
notion image
notion image
这个QWidget实际上是一个窗口= =
如果希望通过纯code方式进行操作,就不能从这个入口进行调用
既然本身是调用的第三方应用程序,为什么一定要显示界面呢?
 
SPIRV-Cross本身是一个独立开源库,github上有使用说明,我们只需要把它需要的数据喂给他执行,就能得到最终结果了。
查看其Github库的Readme可以看到它本身支持通过Command Line Interface进行调用,也就是可以通过cmd调用它的功能
README.md
KhronosGroup
notion image
 
然后稳妥起见我重新打开了Renderdoc的源码工程,想确认一下Renderdoc是如何调用的,最好是能和Renderdoc采用同样的方式调用,这样才会得到相同的结果。
而上文中有提到qrenderdoc.shaderprocessingtool这个类。其文档中有写到需要传递args给目标工具,且有一个DefaultArguments()函数可以获取默认的args
notion image
Renderdoc源码工程中我找到了对应内容,其函数写在PersistantConfig.cpp这个类中:
有没有觉得return内容眼熟?其实就是SPIRV-Cross的Readme中CLI那部分args
所以可以确认这个调用途径是一样的
 

确认调用内容

然后是如何在Python中调用SPIRV-Cross.exe,我直接问的豆包(。
给出的回复是用subprocess这个库可以从Python中调用CLI运行其他程序,大概长这样(实际执行是失败的):
这里reflection_command实际上就是在cmd中输入的指令
spirv_cross_executable就是执行程序的路径(如果用过cmd的同学应该有些印象,指令的第一个内容就是要执行的程序)
这个路径,Renderdoc已经写这儿了 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
notion image
问题出在哪儿呢,出在我们不知道arg实际应该怎么传。
如果你这时候只运行程序不传参数,即写成reflection_command = [spirv_cross_executable] 然后直接调用subprocess.run运行,
实际上是可以在Console界面看到SPIRV-Cross自己提供的args说明,非常全(我只截最上面一点)
notion image
最上面可以看到Log了一句Didn’t specify input file,意思是你调用一定得有一个input的shader file,然后才能转译
而KhronosGroup在这里也没有讲清楚在Args之前需要传入什么内容

确认 Args

经过一些测试之后我发现实际上上述红色提示中[SPIR-V File](- is stdin)指的就是input的shader file,且必须指明。它不像指定output需要-o或者--output 标记,它就跟在可执行程序路径后。
所以command实际上是这样的:
而args部分几经测试后,针对RenderDoc的api中DefaultArguments()返回内容的搜索,可以确认到,我需要使用如下这套args,并且将entry_point与glsl_stage4进行替换以正确设置
查看源码工程可以确认,这里的entry_point等于文档中ShaderReflection.entryPoint转字符串,通常结果是“main”
notion image
  • glsl_stage4在源码中意义就很明显了
notion image
这样所有args内容就都是可以确定下来了

最后一个坑

args确定完,只要传一个正确的input shader file就完成了。ShaderProcessingTool.CompileShader()函数中也需要传递一个str格式的source参数作为source code,那顺理成章的认为传这个进去就行了
notion image
RenderDoc给的官方案例中也提供了输出原Shader File的办法,就是controller.DisassembleShader,最后可以得到shader 文本。顺着这个思路把这个函数调用的结果赋值给字符串,然后把字符串保存成文件就可以做成shader file了。也是有效的,最终这个file也可以查看到,和Renderdoc内打开的默认版本是一样的
notion image
然而实际上执行结果是一行LogError
notion image
😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅
回头又看了一眼SPIRV-Cross的Readme发现他们样例中传入的是一个.spv文件
问了一下豆包才知道.spv是一个二进制文件,不是一个可阅读的版本,那么尬住了,我上哪儿找这个版本的文件
然后回去看了一眼Renderdoc源码发现了盲点
ShaderProcessingTool.DisassembleShader()是这么写的,它传入了一个ShaderReflection:
而Shader ProcessingTool.CompileShader()是这么写的,它传入的source是一个str:
那么很显然,这个可以存储为.spv版本的二进制shader源码,就是ShaderReflection.rawBytes😅😅😅😅😅
notion image
到这儿就结束了。相当于需要把ShaderReflection.rawBytes存成.spv文件然后通过command传给SPIRV-Cross.exe进行转译,这时能得到正确的输出结果。
notion image
这回导出的终于对了,整套流程硬控了我半个月😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅
 
Renderdoc自动化导出重组踩坑(四):您可以直接转HLSL的.jpgRenderdoc自动化导出重组踩坑(二):缺失的样例描述
Loading...