在重度使用compute shader,甚至以其作为核心实现的应用,一个普遍的需求,及工程上困难是如何做好错误处理。
compute shader是需要错误处理的,原因是某些情况下:
- 用户输入可能是非法的,且无法在host端提前以合理的成本检查用户输入
- 所谓没有合理的成本的一个极端假设是执行输入验证的成本和执行整个workload相当,而使得在host上做错误处理失去实际意义
- 执行所需的资源准备可能是不充分的,且无法在执行前以合理的成本确定资源需求
- 执行所需的资源不能在执行前确定,原因主要是某些逻辑涉及到gpu上的动态内存分配和动态执行宽度。而资源又无法在执行时扩容,所以就可能会导致没有足够的临时空间来完成计算。具体的例子比如bumpallocator预分配内存不足导致分配失败。
- 所谓成本原因和上述用户输入验证的理由一致,即无法以合理的成本计算出完成计算的中间动态资源需求
错误处理在工程上的困难在于:
- 所有dispatch command都是提前录制的,无法在command层面跳过出问题的dispatch后续的所有dispatch。只能在compute shader 内跳过。具体来说有以下:
- 只能在所有shader内去check某些状态来跳过自身执行
- 记录错误信息,状态 而手工的实现和正确处理这些细节,非常繁琐易错。
- compute shader 没有abort方法,无法做到在一个shader内,出错后,简单的跳过后续所有shader逻辑
上述的困难中的第一点,是可以在工程上作出改进的,所以基于shader edsl api和其他基础设施,可考虑实现这样的错误处理解决方案:
- 在queue和command encoder上封装相关能力,track dispatch,buffer,texture之间的读写关系,以此分析出dispatch之间的依赖关系
- 根据上述分析出来的执行依赖图,自动的,全局的分配和维护per dispatch的错误信息记录buffer,并为每一个dispatch,在shader内自动的注入跳过逻辑。以实现dispatch级别的错误降级
- compute shader ctx api提供错误信息记录能力。其中包括device上log,及错误信息的字符串format(这些并不依赖于平台api,可以通过直接拼写utf8 byte来巧妙实现)
- dispatch返回执行结果的能够async read,让host端可以连续的异步的检查之前帧的执行结果,获得具体的错误信息。
- 在渲染处于短暂的出错状态时,实现上应该提供降级的表现,而不至于崩溃。
- 如果对渲染结果的正确性有极高要求,即完全不出错,那么可能需要heroic级别的工程实现:
- 确保让async check结束之后才上屏显示,如果check失败则立刻重新扩容执行。一般这么做是不建议的,一方面实现会很复杂,另一方面会引入巨大的延迟。应该简单对容量做估计和hint,来尽可能避免降级实现出现。
- 如果对渲染结果的正确性有极高要求,即完全不出错,那么可能需要heroic级别的工程实现:
- 在渲染处于短暂的出错状态时,实现上应该提供降级的表现,而不至于崩溃。