Compose 渲染内核 (6):穿透抽象 —— 直接调用 Skia 原生 API

23 阅读2分钟

前言

我们在前面的章节讨论了 DrawScope。但有时候,DrawScope 提供的通用 API 无法满足我们对极致视觉效果的追求,比如复杂的着色器(Shaders)、滤镜(Filters)或者底层的 Path 运算。

由于 Compose Multiplatform (CMP) 底层就是 Skia,我们完全可以“穿透”抽象层,直接与 Skia 对话。


一、 获取 NativeCanvas 的入场券

在 Compose 的绘制逻辑中,你可以通过以下方式拿到底层的 Canvas 对象:

Canvas(modifier = Modifier.fillMaxSize()) {
    drawIntoCanvas { canvas ->
        val nativeCanvas = canvas.nativeCanvas
        // 现在你可以调用 Skia 的 C++ 指令映射了!
    }
}
  • Android 上nativeCanvas 返回的是 android.graphics.Canvas
  • CMP(Desktop/iOS/Web)上:返回的是 org.jetbrains.skia.Canvas

二、 Skia 级的功能增强

当你拿到原生 Canvas 后,你可以解锁以下“禁术”:

  1. Runtime Shaders (AGSL): 编写类似于 GLSL 的着色器代码,在像素级别控制光影效果(如流光溢彩、波浪纹)。
  2. 高级 Path 运算: 直接调用 Skia 的 Path 混合、裁剪和复杂描边算法。
  3. 颜色滤镜 (ColorFilter): 使用 Skia 内置的矩阵滤镜实现电影级的调色。

三、 实战案例:跨平台 Shader 动效

利用我们在本项目中学到的 Native 调用 思想:

  1. commonMain 定义绘制接口。
  2. 利用 Skiko 提供的 org.jetbrains.skia.* 类库。
  3. 编写一套 100% 共享的 Skia 绘图指令,在 Android 和 iOS 上渲染出完全一致的高级动效。

四、 性能警告

穿透抽象是有代价的:

  • 状态管理失效:当你绕过 Compose API 直接操作 nativeCanvas 时,Compose 无法自动追踪你的状态变化。你必须手动触发 invalidate
  • 跨端差异:虽然 CMP 使用 Skia,但不同平台的显卡驱动(Driver)对特定 Shader 的支持程度可能不同。

五、 职业进阶建议

如果你能掌握 Skia 的原生调用,你将具备开发以下产品的能力:

  • 跨端图形设计软件(如类似 Figma 的工具)。
  • 高性能图表库。
  • 高度自定义的游戏引擎 UI。

🏗️ 源码关键点

  • androidx.compose.ui.graphics.drawscope.drawIntoCanvas
  • org.jetbrains.skia.Canvas (CMP 专属)

结语

直接调用 Skia 是 Compose 开发的“最高权限”。它让 Kotlin 拥有了直接操控显卡的能力。

下一篇,我们将讨论图形 API 的跨端适配:Metal (iOS) vs Vulkan (Android) vs OpenGL (Web)