You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

三星S21设备上AGSL着色器无法正常动画的问题

AGSL着色器在三星S21(API 34)上动画仅运行1帧后停止的问题排查与解决

问题概述

在Android Studio API 34可调整大小模拟器中,AGSL着色器的时间动画可正常运行,但在同API等级的三星S21设备上,着色器的时间动画仅执行1帧后便停止。该问题并非特定着色器代码导致,采用相同实现方式的其他AGSL着色器在三星S21上均出现此异常。

代码问题分析

从提供的代码来看,存在几个可能触发设备端异常的点:

  • 协程调度冗余:produceState内部在withInfiniteAnimationFrameMillis回调中额外启动launch协程更新value,可能导致帧回调的时间更新被延迟或丢失,尤其在三星设备的协程调度逻辑下。
  • RenderEffect缓存机制:graphicsLayer中创建RenderEffect未显式依赖time变量,三星设备的GPU可能会缓存初始的RenderEffect,后续time更新时不会触发重新渲染。
  • Uniform更新时机:在graphicsLayer中直接设置time uniform,可能与RenderEffect的创建时机不匹配,导致uniform更新未被同步到渲染管线。

解决方案

方案1:简化produceState的协程逻辑

去掉withInfiniteAnimationFrameMillis内部的launch协程,直接同步更新value,确保每帧时间都能及时传递:

val time by produceState(0f) {
    while (true) {
        withInfiniteAnimationFrameMillis { frameTime ->
            value = if (clockUiState.showAnimations) {
                frameTime / 1000f
            } else {
                1000f // 无需delay,关闭动画时固定值即可
            }
        }
    }
}

方案2:确保RenderEffect随time更新

用remember(time)包裹RenderEffect的创建,强制每次time变化时重新生成渲染效果,避免GPU缓存:

.graphicsLayer {
    matrixShader.setFloatUniform("time", time)
    renderEffect = remember(time) {
        RenderEffect.createRuntimeShaderEffect(matrixShader, "contents")
            .asComposeRenderEffect()
    }
}

方案3:分离Uniform更新与RenderEffect创建

将uniform的更新放到LaunchedEffect中,确保time变化时优先更新uniform,再同步更新RenderEffect:

// 单独处理time uniform的更新
LaunchedEffect(time) {
    matrixShader.setFloatUniform("time", time)
}

Canvas(modifier = Modifier
    .fillMaxSize()
    .onSizeChanged { size ->
        matrixShader.setFloatUniform("resolution", size.width.toFloat(), size.height.toFloat())
    }
    .graphicsLayer {
        renderEffect = remember(time) {
            RenderEffect.createRuntimeShaderEffect(matrixShader, "contents")
                .asComposeRenderEffect()
        }
    }
) {
    drawRect(Color.Red)
}

方案4:禁用GraphicsLayer缓存(极端场景)

如果上述方案均无效,可尝试禁用graphicsLayer的缓存,强制每次重组都重新渲染(注意:会增加性能开销,适合桌面支架这类对功耗容忍度较高的场景):

.graphicsLayer(disableCache = true) {
    matrixShader.setFloatUniform("time", time)
    renderEffect = RenderEffect.createRuntimeShaderEffect(matrixShader, "contents")
        .asComposeRenderEffect()
}

验证步骤

  1. 优先尝试方案1,这是最可能解决协程调度导致的帧更新丢失问题。
  2. 若方案1无效,执行方案2,确保RenderEffect随时间变量重新创建。
  3. 仍未解决则尝试方案3,分离uniform更新与渲染效果创建的逻辑。
  4. 最后考虑方案4,禁用缓存强制更新。

内容的提问来源于stack exchange,提问作者Matthollemue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:25:34