SkSL着色器多大算‘过大’?如何使用更大的着色器?
SkSL着色器「program is too large」问题解决方案
问题描述
我通过Compose渲染片段着色器(代码示例如下),尝试移植ShaderToy中的代码。SkSL与GLSL语法相近,多数ShaderToy着色器只需少量修改即可运行,但频繁碰到「program is too large」异常,尤其在包含大量循环的光线步进着色器中。该着色器在浏览器GLSL环境可正常运行,现咨询如何提升SkSL着色器的大小限制。
代码示例
fun main() = singleWindowApplication(title = "Shaaaderrrs") { val runtimeEffect = remember { RuntimeEffect.makeForShader( """ uniform vec3 iResolution; vec4 main(in vec2 fragCoord) { return vec4(fragCoord / iResolution.xy, 0, 1); } """.trimIndent() ) } val shader by derivedStateOf { val builder = RuntimeShaderBuilder(runtimeEffect) builder.uniform("iResolution", 800.0f, 600.0f, 1.0f) builder.makeShader() } val brush by derivedStateOf { ShaderBrush(shader) } Surface(modifier = Modifier.background(MaterialTheme.colors.surface)) { Canvas(modifier = Modifier.fillMaxSize()) { drawRect(brush = brush, size = Size(800.0f, 600.0f)) } } }
异常信息
java.lang.RuntimeException: error: program is too large 1 error at org.jetbrains.skia.RuntimeEffectKt._nMakeForShader(Native Method) at org.jetbrains.skia.RuntimeEffectKt.access$_nMakeForShader(RuntimeEffect.kt:1) at org.jetbrains.skia.RuntimeEffect$Companion.makeForShader(RuntimeEffect.kt:11) at com.example.common.ShaderToyKt.ShaderToy(ShaderToy.kt:46) at com.example.common.AppKt.App(App.kt:8)
解决思路与方案
Skia的RuntimeEffect对着色器代码大小有内置限制,目的是避免性能过载或资源过度占用。可从以下方向尝试解决:
- 精简冗余代码:删除注释、未使用的变量/函数、无效分支逻辑;将重复计算封装成公共函数,减少代码冗余。
- 优化循环逻辑:光线步进着色器中,设置更合理的循环终止条件(比如基于距离阈值提前退出),减少不必要的迭代次数;尝试用数学公式替代部分循环计算。
- 代码压缩:用SkSL专用工具压缩代码,移除空格、换行等非必要符号,在不破坏语法的前提下缩小代码体积。
- 拆分着色器逻辑:将复杂着色器拆分为多个RuntimeEffect,通过纹理传递中间结果。比如把光线步进的不同阶段拆分成独立着色器,前一个的输出纹理作为后一个的输入,降低单个着色器的代码量。
- 升级Skia版本:确保使用最新版的Compose(间接依赖最新Skia),新版本可能放宽代码大小限制或修复相关判断逻辑的bug。
- 谨慎展开循环:对于固定次数的循环,手动展开循环语句减少循环控制代码,但仅适合循环次数较少的场景,避免代码体积反向增加。
内容的提问来源于stack exchange,提问作者Hakanai
相关产品推荐
相关产品推荐

