如果 USAGE_SHARED,Renderscript 在启用 GPU 的驱动程序上失败
Renderscript fails on GPU enabled driver if USAGE_SHARED
我们正在使用 renderscript 进行音频 dsp 处理。它很简单,并且可以显着提高我们用例的性能。但是我们 运行 在具有启用了 GPU 执行的自定义驱动程序的设备上 USAGE_SHARED
遇到了一个烦人的问题。
如您所知,USAGE_SHARED
标志使渲染脚本分配重用给定的内存,而无需创建它的副本。因此,它不仅可以节省内存,在我们的例子中,还可以将性能提高到所需的水平。
以下带有 USAGE_SHARED
的代码在默认渲染脚本驱动程序 (libRSDriver.so
) 上运行良好。使用自定义驱动程序 (libRSDriver_adreno.so
) USAGE_SHARED
不会重用给定的内存和数据。
这是使用 USAGE_SHARED
并调用 renderscript 内核的代码
void process(float* in1, float* in2, float* out, size_t size) {
sp<RS> rs = new RS();
rs->init(app_cache_dir);
sp<const Element> e = Element::F32(rs);
sp<const Type> t = Type::create(rs, e, size, 0, 0);
sp<Allocation> in1Alloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
in1);
sp<Allocation> in2Alloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
in2);
sp<Allocation> outAlloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
out);
ScriptC_x* rsX = new ScriptC_x(rs);
rsX->set_in1Alloc(in1Alloc);
rsX->set_in2Alloc(in2Alloc);
rsX->set_size(size);
rsX->forEach_compute(in1Alloc, outAlloc);
}
注意:文档中未提及 Allocation::createTyped()
的这种变体,但代码 rsCppStructs.h
中有。这是允许提供后备指针并尊重 USAGE_SHARED
标志的分配工厂方法。这是它的声明方式:
/**
* Creates an Allocation for use by scripts with a given Type and a backing pointer. For use
* with RS_ALLOCATION_USAGE_SHARED.
* @param[in] rs Context to which the Allocation will belong
* @param[in] type Type of the Allocation
* @param[in] mipmaps desired mipmap behavior for the Allocation
* @param[in] usage usage for the Allocation
* @param[in] pointer existing backing store to use for this Allocation if possible
* @return new Allocation
*/
static sp<Allocation> createTyped(
const sp<RS>& rs, const sp<const Type>& type,
RsAllocationMipmapControl mipmaps,
uint32_t usage,
void * pointer);
这是渲染脚本内核
rs_allocation in1Alloc, in2Alloc;
uint32_t size;
// JUST AN EXAMPLE KERNEL
// Not using reduction kernel since it is only available in later API levels.
// Not sure if support library helps here. Anyways, unrelated to the current problem
float compute(float ignored, uint32_t x) {
float result = 0.0f;
for (uint32_t i=0; i<size; i++) {
result += rsGetElementAt_float(in1Alloc, x) * rsGetElementAt_float(in2Alloc, size-i-1); // just an example computation
}
return result;
}
如前所述,out
没有任何计算结果。
syncAll(RS_ALLOCATION_USAGE_SHARED)
也没有帮助。
下面的虽然有效(但慢得多)
void process(float* in1, float* in2, float* out, size_t size) {
sp<RS> rs = new RS();
rs->init(app_cache_dir);
sp<const Element> e = Element::F32(rs);
sp<const Type> t = Type::create(rs, e, size, 0, 0);
sp<Allocation> in1Alloc = Allocation::createTyped(rs, t);
in1Alloc->copy1DFrom(in1);
sp<Allocation> in2Alloc = Allocation::createTyped(rs, t);
in2Alloc->copy1DFrom(in2);
sp<Allocation> outAlloc = Allocation::createTyped(rs, t);
ScriptC_x* rsX = new ScriptC_x(rs);
rsX->set_in1Alloc(in1Alloc);
rsX->set_in2Alloc(in2Alloc);
rsX->set_size(size);
rsX->forEach_compute(in1Alloc, outAlloc);
outAlloc->copy1DTo(out);
}
复制可以正常工作,但在我们的测试中,来回复制会显着降低性能。
如果我们通过 debug.rs.default-CPU-driver
系统 属性 关闭 GPU 执行,我们可以看到自定义驱动程序运行良好,具有所需的性能。
将分配给 renderscript 的内存对齐到 16,32,.., 或 1024 等无助于使自定义驱动程序尊重 USAGE_SHARED。
问题
因此,我们的问题是:如何使该内核适用于使用启用 GPU 执行的自定义渲染脚本驱动程序的设备?
即使使用USAGE_SHARED也需要副本。
USAGE_SHARED只是给驱动的一个提示,不一定要用。
如果驱动程序确实共享内存,则副本将被忽略,性能将相同。
我们正在使用 renderscript 进行音频 dsp 处理。它很简单,并且可以显着提高我们用例的性能。但是我们 运行 在具有启用了 GPU 执行的自定义驱动程序的设备上 USAGE_SHARED
遇到了一个烦人的问题。
如您所知,USAGE_SHARED
标志使渲染脚本分配重用给定的内存,而无需创建它的副本。因此,它不仅可以节省内存,在我们的例子中,还可以将性能提高到所需的水平。
以下带有 USAGE_SHARED
的代码在默认渲染脚本驱动程序 (libRSDriver.so
) 上运行良好。使用自定义驱动程序 (libRSDriver_adreno.so
) USAGE_SHARED
不会重用给定的内存和数据。
这是使用 USAGE_SHARED
并调用 renderscript 内核的代码
void process(float* in1, float* in2, float* out, size_t size) {
sp<RS> rs = new RS();
rs->init(app_cache_dir);
sp<const Element> e = Element::F32(rs);
sp<const Type> t = Type::create(rs, e, size, 0, 0);
sp<Allocation> in1Alloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
in1);
sp<Allocation> in2Alloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
in2);
sp<Allocation> outAlloc = Allocation::createTyped(
rs, t,
RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
out);
ScriptC_x* rsX = new ScriptC_x(rs);
rsX->set_in1Alloc(in1Alloc);
rsX->set_in2Alloc(in2Alloc);
rsX->set_size(size);
rsX->forEach_compute(in1Alloc, outAlloc);
}
注意:文档中未提及 Allocation::createTyped()
的这种变体,但代码 rsCppStructs.h
中有。这是允许提供后备指针并尊重 USAGE_SHARED
标志的分配工厂方法。这是它的声明方式:
/**
* Creates an Allocation for use by scripts with a given Type and a backing pointer. For use
* with RS_ALLOCATION_USAGE_SHARED.
* @param[in] rs Context to which the Allocation will belong
* @param[in] type Type of the Allocation
* @param[in] mipmaps desired mipmap behavior for the Allocation
* @param[in] usage usage for the Allocation
* @param[in] pointer existing backing store to use for this Allocation if possible
* @return new Allocation
*/
static sp<Allocation> createTyped(
const sp<RS>& rs, const sp<const Type>& type,
RsAllocationMipmapControl mipmaps,
uint32_t usage,
void * pointer);
这是渲染脚本内核
rs_allocation in1Alloc, in2Alloc;
uint32_t size;
// JUST AN EXAMPLE KERNEL
// Not using reduction kernel since it is only available in later API levels.
// Not sure if support library helps here. Anyways, unrelated to the current problem
float compute(float ignored, uint32_t x) {
float result = 0.0f;
for (uint32_t i=0; i<size; i++) {
result += rsGetElementAt_float(in1Alloc, x) * rsGetElementAt_float(in2Alloc, size-i-1); // just an example computation
}
return result;
}
如前所述,out
没有任何计算结果。
syncAll(RS_ALLOCATION_USAGE_SHARED)
也没有帮助。
下面的虽然有效(但慢得多)
void process(float* in1, float* in2, float* out, size_t size) {
sp<RS> rs = new RS();
rs->init(app_cache_dir);
sp<const Element> e = Element::F32(rs);
sp<const Type> t = Type::create(rs, e, size, 0, 0);
sp<Allocation> in1Alloc = Allocation::createTyped(rs, t);
in1Alloc->copy1DFrom(in1);
sp<Allocation> in2Alloc = Allocation::createTyped(rs, t);
in2Alloc->copy1DFrom(in2);
sp<Allocation> outAlloc = Allocation::createTyped(rs, t);
ScriptC_x* rsX = new ScriptC_x(rs);
rsX->set_in1Alloc(in1Alloc);
rsX->set_in2Alloc(in2Alloc);
rsX->set_size(size);
rsX->forEach_compute(in1Alloc, outAlloc);
outAlloc->copy1DTo(out);
}
复制可以正常工作,但在我们的测试中,来回复制会显着降低性能。
如果我们通过 debug.rs.default-CPU-driver
系统 属性 关闭 GPU 执行,我们可以看到自定义驱动程序运行良好,具有所需的性能。
将分配给 renderscript 的内存对齐到 16,32,.., 或 1024 等无助于使自定义驱动程序尊重 USAGE_SHARED。
问题
因此,我们的问题是:如何使该内核适用于使用启用 GPU 执行的自定义渲染脚本驱动程序的设备?
即使使用USAGE_SHARED也需要副本。
USAGE_SHARED只是给驱动的一个提示,不一定要用。
如果驱动程序确实共享内存,则副本将被忽略,性能将相同。