三星Galaxy S8上的RenderScript性能低下

S. *_*ert 13 performance animation android renderscript samsung-s8

语境

我有一个Android应用,需要一个图象,模糊的图像,去除模糊基于掩模和施加最终层(不相关)。最后两个步骤(基于蒙版消除模糊并应用最后一层)重复进行,每次使用一个新蒙版(150个蒙版)。

输出get绘制在画布(SurfaceView)上。这样,应用程序可以有效地创建具有动画模糊效果的图像视图。

技术细节和代码

所有这些图像处理步骤都是使用RenderScript实现的。

我将第1步的代码省略掉,使图片模糊,因为这与我要面对的问题无关。

步骤2:消除基于蒙版的模糊

我有一个自定义内核,该内核in Allocation作为参数并包含2个全局变量,这也是Allocations

这3个分配都使用Allocation.copyFrom(bitmap)从位图获取数据。

第三步:应用最后一层

在这里,我还有一个自定义内核,该内核in Allocation作为参数并包含3个全局变量,其中1是和Allocation,2是浮点数

这些内核的工作方式与这个问题无关,但是为了确保我在下面包括了一些简化的片段。

还要注意的另一件事是,我正在遵循所有最佳实践,以确保有关分配,RenderScript和我的SurfaceView的性能达到最佳状态。

因此,可以忽略常见的错误,例如每次创建一个新的RenderScript实例,不尽可能重用Allocations。

blurMask.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);
}
Run Code Online (Sandbox Code Playgroud)

myKernel.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);
}
Run Code Online (Sandbox Code Playgroud)

问题

因此,该应用程序在各种设备(即使是低端设备)上都可以很好地运行。我手动将FPS的上限设置为15,但是当我取下上限时,得到的结果范围从低端设备上的15-20到高端设备上的35-40。

三星Galaxy S8是哪里出现了问题。由于某种原因,我只能设法达到10 FPS。如果我使用adb强制RenderScript改为使用CPU:

adb shell setprop debug.rs.default-CPU-driver 1
Run Code Online (Sandbox Code Playgroud)

我得到大约12-15 FPS,但显然我希望它在GPU上运行。

我注意到的一件重要而奇怪的事情

如果我触发了触摸事件,则无论在何处(甚至不在应用程序中),性能都会显着提高到35-40 FPS。如果我再次从屏幕上抬起手指,FPS会降回10 FPS。

注意:可以将在SurfaceView上绘制结果作为影响因素排除在外,因为结果与RenderScript中的计算相同,而没有绘制实际结果。

问题

所以我确实有多个问题:

  • 性能低下的原因可能是什么?
  • 为什么触摸事件会如此显着地改善此性能?
  • 我该如何解决或解决此问题?