android - 三星 Galaxy S8 上的 RenderScript 性能低下
问题描述
语境
我有一个 Android 应用程序,它可以拍照、模糊图片、根据蒙版去除模糊并应用最后一层(不相关)。最后两个步骤,基于蒙版去除模糊并应用最后一层重复完成,每次使用新蒙版(150 个蒙版)。
输出在画布 (SurfaceView) 上绘制。通过这种方式,应用程序有效地创建了带有动画模糊的图像视图。
技术细节和代码
所有这些图像处理步骤都是通过RenderScript实现的。
我省略了步骤 1 的代码,模糊了图片,因为这与我面临的问题无关。
第 2 步:根据蒙版去除模糊
我有一个自定义内核,它以in 分配作为参数并保存2 个全局变量,它们也是分配。
这 3 个分配都使用Allocation.copyFrom(bitmap)从位图中获取数据。
第 3 步:应用最后一层
在这里,我还有一个自定义内核,它以in Allocation作为参数并保存3 个全局变量,其中 1 个是和Allocation,2 个是浮点数。
这些内核如何工作与这个问题无关,但只是为了确保我在下面包含了一些简化的片段。
需要注意的另一件事是,我遵循所有最佳实践以确保在分配、RenderScript 和我的 SurfaceView 方面的性能处于最佳状态。
所以常见的错误,比如每次都创建一个新的 RenderScript 实例,在可能的情况下不重新使用分配,.. 是可以安全忽略的。
模糊面具.rs
#pragma version(1)
#pragma rs java_package_name(com.example.rs)
#pragma rs_fp_relaxed
// Extra allocations
rs_allocation allocBlur;
rs_allocation allocBlurMask;
/*
* RenderScript kernel that performs a masked blur manipulation.
* Blur Pseudo: out = original * blurMask + blur * (1.0 - blurMask)
* -> Execute this for all channels
*/
uchar4 __attribute__((kernel)) blur_mask(uchar4 inOriginal, uint32_t x, uint32_t y) {
// Manually getting current element from the blur and mask allocations
uchar4 inBlur = rsGetElementAt_uchar4(allocBlur, x, y);
uchar4 inBlurMask = rsGetElementAt_uchar4(allocBlurMask, x, y);
// normalize to 0.0 -> 1.0
float4 inOriginalNorm = rsUnpackColor8888(inOriginal);
float4 inBlurNorm = rsUnpackColor8888(inBlur);
float4 inBlurMaskNorm = rsUnpackColor8888(inBlurMask);
inBlurNorm.rgb = inBlurNorm.rgb * 0.7 + 0.3;
float4 outNorm = inOriginalNorm;
outNorm.rgb = inOriginalNorm.rgb * inBlurMaskNorm.rgb + inBlurNorm.rgb * (1.0 - inBlurMaskNorm.rgb);
return rsPackColorTo8888(outNorm);
}
我的内核.rs
#pragma version(1)
#pragma rs java_package_name(com.example.rs)
#pragma rs_fp_relaxed
// Extra allocations
rs_allocation allocExtra;
// Randoms; Values are set from kotlin, the values below just act as a min placeholder.
float randB = 0.1f;
float randW = 0.75f;
/*
* RenderScript kernel that performs a manipulation.
*/
uchar4 __attribute__((kernel)) my_kernel(uchar4 inOriginal, uint32_t x, uint32_t y) {
// Manually getting current element from the extra allocation
uchar4 inExtra = rsGetElementAt_uchar4(allocExtra, x, y);
// normalize to 0.0 -> 1.0
float4 inOriginalNorm = rsUnpackColor8888(inOriginal);
float4 inExtraNorm = rsUnpackColor8888(inExtra);
float4 outNorm = inOriginalNorm;
if (inExtraNorm.r > 0.0) {
outNorm.rgb = inOriginalNorm.rgb * 0.7 + 0.3;
// Separate channel operation since we are using inExtraNorm.r everywhere
outNorm.r = outNorm.r * inExtraNorm.r + inOriginalNorm.r * (1.0 - inExtraNorm.r);
outNorm.g = outNorm.g * inExtraNorm.r + inOriginalNorm.g * (1.0 - inExtraNorm.r);
outNorm.b = outNorm.b * inExtraNorm.r + inOriginalNorm.b * (1.0 - inExtraNorm.r);
}
else if (inExtraNorm.g > 0.0) {
...
}
return rsPackColorTo8888(outNorm);
}
问题
因此,该应用程序在一系列设备上运行良好,即使在低端设备上也是如此。我手动将 FPS 上限设置为 15,但当我取消此上限时,我得到的结果从低端设备上的 15-20 到高端设备上的 35-40 不等。
三星 Galaxy S8是我出现问题的地方。出于某种原因,我只能达到 10 FPS 左右。如果我使用adb强制 RenderScript 使用 CPU:
adb shell setprop debug.rs.default-CPU-driver 1
我得到大约 12-15 FPS,但显然我希望它在 GPU 上运行。
我注意到一件重要的、奇怪的事情
如果我触发一个触摸事件,无论在哪里(甚至在应用程序之外),性能都会显着提高到 35-40 FPS 左右。如果我再次将手指从屏幕上移开,FPS 会回落到 10 FPS。
注意:在 SurfaceView 上绘制结果可以作为影响因素排除,因为结果与 RenderScript 中的计算相同,而不绘制实际结果。
问题
所以我真的有不止一个问题:
- 性能低下的原因可能是什么?
- 为什么触摸事件会如此显着地提高这种性能?
- 我该如何解决或解决此问题?
解决方案
推荐阅读
- reactjs - ReactDOMServer.renderToString() - 它到底是做什么的?
- python - 如何创建滚动窗口函数来检测python中时间序列数据集中的峰值?
- cordova - AndroidSDK Apk 创建与 Ionic Cordova 产品构建
- kde - 如何阻止非活动窗口接受鼠标输入?(KDE Plasma / Debian Buster / FreeRDP)
- parsing - 是什么决定了解析器尝试哪个产生式?
- javascript - 检查 html 表单中的 angular observables 的值时出错 *ngIf="**!** currentUserNav$ | async"
- javascript - Expo / React Native:ellipsizeMode和数字TextInput?
- r - 如何使用带有特殊 seq 的 for 循环
- python - sys.exit() 导致意外错误导致“repl 进程意外死亡”
- javascript - 单元测试反应容器组件