Мы используем Renderscript для обработки аудио DSP.Это просто и значительно повышает производительность для нашего варианта использования.Но мы сталкиваемся с досадной проблемой с 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
, мы увидим, что пользовательский драйвер хорошо работает с желаемой производительностью.
Выравнивание памяти, выделенной для Renderscript16,32, .., или 1024, и т. д. не помогли заставить пользовательский драйвер уважать USAGE_SHARED.
Вопрос
Итак, наш вопрос таков: как заставить это ядро работать дляустройства, использующие пользовательский драйвер рендеринга, который обеспечивает выполнение графического процессора?