Android - RenderScript - SDK 21 中的性能下降



我正在开发一个需要复杂Photoshop类型混合效果的项目。我正在使用自定义RenderScript脚本来解决此问题。

我一直在运行KitkatSamsung Galaxy S4设备上对其进行测试,一切都运行良好且非常快。

然后,我尝试在运行棒棒糖Nexus 5上测试它,我注意到性能突然下降。

我开始对代码中的不同部分进行计时,以查看哪些部分变慢了,并提出了这个:

Allocation.createFromBitmap
- Runtime on Kitkat - ~5-10 millisec
- Runtime on Lollipop - ~100-150 millisec
mRenderScript.destory()
- Runtime on Kitkat - ~1-3 millisec
- Runtime on Lollipop - ~60-100 millisec

我很好奇为什么在应该更强大的设备上创建Allocation对象并销毁RenderScript对象时性能突然下降,而在应该更先进的操作系统上。

对于API 21 OS,我可以做些什么来使这些方法运行得更快吗?

有没有人遇到过这个问题或可以重现它?

我应该注意,脚本的实际运行(即ScriptC.forEach方法(在两个设备/操作系统上运行得非常快。此外,我使用的是本机RenderScript API,而不是任何支持库。

任何意见将不胜感激。

编辑:

我在这里复制了 Github of Allocation 中 Android 棒棒糖发布源代码的相关行.java

static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
        if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
            return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
                                    USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
        }
        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
                                USAGE_GRAPHICS_TEXTURE);
    }

请注意,当目标 SDK 高于 17 时,默认情况下会使用 USAGE_SHARED 标志创建分配。可能是这些额外的标志导致了问题吗?我应该改用USAGE_GRAPHICS_TEXTURE标志吗?

编辑 2

按照 R. Jason Sam 的建议,当 Nexus 5 连接到我的计算机时,我运行了以下脚本:

adb shell setprop debug.rs.default-CPU-driver 1

在此之后,所述函数的运行时间明显更快(分别为~30-40毫秒和20-50毫秒(。仍然不如棒棒糖前设备快,但在可接受的性能范围内。

我对这个解决方案的唯一问题是,除非我不明白什么,否则不能被视为解决方案,因为它需要我在运行应用程序之前在每个有问题的设备上调用此脚本。

我可以在我的代码中做些什么来模拟这个 adb 调用吗?

最终编辑

好的,所以问题似乎源于这样一个事实,即每次调用使用 RenderScript 执行混合效果的函数时,我都会创建一个新的 RenderScript 对象。

做了一些代码重构,现在,我每次都重复使用相同的对象,而不是在每次调用效果方法时创建一个新的 RenderScript 对象。在 Lollipop 设备上创建 RenderScript 对象的第一次创建仍然需要更长的时间,但现在问题得到了缓解,因为我继续在多个方法调用中重用同一个对象。

我将添加此作为答案。

似乎

问题源于这样一个事实,即每次调用使用 RenderScript 执行混合效果的函数时,我都会创建一个新的 RenderScript 对象。

做了一些代码重构,现在,我每次都重复使用相同的对象,而不是在每次调用效果方法时创建一个新的 RenderScript 对象。在 Lollipop 设备上创建 RenderScript 对象的第一个创建仍然需要更长的时间,但现在问题得到了缓解,因为我继续在多个方法调用中重用同一个对象。

一旦我确定不再需要共享RenderScript对象,我确保在共享对象上调用destory()以确保没有内存泄漏。

根据这篇文章,重用RenderScript对象而不是每次都创建一个新对象似乎是公平的做法,但我很高兴听到其他人关于他们对此事的经验的意见。很遗憾,网上没有太多关于这个主题的文档,但到目前为止,一切似乎在多个设备/操作系统上都运行良好。

在 Api 18 (USAGE_SHARED( 中添加了一个分配类型。 如果您强制 Renderscript 复制位图支持内存(而不是就地使用它(,则可能需要解释差异。

 Allocation tmpOut = Allocation.createFromBitmap(mRenderContext, result, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SHARED);

最新更新