如果USAGE_SHARED

时间:2018-05-27 04:20:19

标签: android performance signal-processing renderscript android-renderscript

我们正在使用renderscript进行音频dsp处理。它很简单,并且对我们的用例显着提高了性能。但是,对于具有启用GPU执行的自定义驱动程序的设备,USAGE_SHARED遇到了令人讨厌的问题。

您可能知道,USAGE_SHARED标志使renderscript分配重用给定的内存而不必创建它的副本。因此,在我们的案例中,它不仅可以节省内存,还可以将性能提升到所需的水平。

以下代码USAGE_SHARED在默认的renderscript驱动程序(libRSDriver.so)上运行正常。使用自定义驱动程序(libRSDriver_adreno.soUSAGE_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);

这是renderscript内核

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执行的自定义renderscript驱动程序的设备?

1 个答案:

答案 0 :(得分:2)

即使您使用USAGE_SHARED,也需要获得副本。

USAGE_SHARED只是对驱动程序的提示,它不必使用它。

如果驱动程序共享内存,则副本将被忽略,性能将相同。