首页 > 解决方案 > 三星 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 中的计算相同,而不绘制实际结果。

问题

所以我真的有不止一个问题:

标签: androidperformanceanimationrenderscriptsamsung-s8

解决方案


推荐阅读