Какие функции ядра вы можете создать в Renderscript?
Фон
Я учусь использовать Renderscript, и я нашел эту часть в документации:
В большинстве случаев это идентично стандартной функции C. Первая заметная особенность - это атрибут((ядро)), применяемый к прототипу функции.
и они показывают пример кода функции ядра:
uchar4 __attribute__((kernel)) invert(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
out.r = 255 - in.r;
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}
Эта проблема
Кажется, что некоторые примеры показывают, что параметры функций ядра могут отличаться, а не только те, что указаны выше.
Пример:
uchar4 __attribute__((kernel)) grayscale(uchar4 v_in) {
float4 f4 = rsUnpackColor8888(v_in);
float3 mono = dot(f4.rgb, gMonoMult);
return rsPackColorTo8888(mono);
}
Дело в том, что сгенерированная функция на Java все та же для всех этих функций:
void forEach_FUNCTIONNAME(Allocation ain, Allocation aout)
где FUNCTIONNAME - это имя функции в RS.
Поэтому я предполагаю, что не каждая возможная функция может быть функцией ядра, и все они должны следовать некоторым правилам (кроме части "атрибут(ядро)", которую необходимо добавить).
Тем не менее я не могу найти эти правила.
Единственное, что я нашел, это на документах:
Ядро может иметь входное распределение, выходное распределение или оба. Ядро не может иметь более одного входного или одного выходного распределения. Если требуется более одного ввода или вывода, эти объекты должны быть связаны с глобальными переменными скрипта rs_allocation и доступны из ядра или вызываемой функции через rsGetElementAt_type() или rsSetElementAt_type(). Ядро может получить доступ к координатам текущего выполнения, используя аргументы x, y и z. Эти аргументы являются необязательными, но тип аргументов координат должен быть uint32_t.
Вопросы
Каковы правила для создания функций ядра, кроме того, что написано?
Какие другие параметры разрешены? Я имею в виду, какие еще параметры я могу передать? Могу ли я использовать только те 2 "шаблона" функций, или я могу использовать другие функции ядра, которые имеют другие наборы параметров?
Есть ли список допустимых функций ядра? Тот, который показывает, какие наборы параметров разрешены?
Могу ли я настроить эти функции ядра, чтобы иметь больше параметров? Например, если бы у меня была функция размытия (я знаю, что у нас есть встроенная), я мог бы установить радиус и алгоритм размытия.
В основном все эти вопросы примерно одинаковы
2 ответа
Там действительно не так много правил. Вы должны иметь или вход, и / или выход, потому что ядра выполняются в имеющемся там диапазоне (т. Е. У вас есть двумерное распределение с x=200, y=400 - оно будет выполняться в каждой ячейке ввода / вывода). Мы поддерживаем запуск без выделения ресурсов, но он доступен только в последней версии Android и, следовательно, не может использоваться на большинстве устройств. Мы также поддерживаем множественный ввод с Android M, но более ранние целевые API не будут работать с этим (если вы не используете библиотеку совместимости).
Параметрами обычно являются примитивные типы (char, int, unsigned int, long, float, double, ...) или векторные типы (например, float4, int2, ...). Вы также можете использовать структуры при условии, что они не содержат указателей в своем определении. Вы не можете использовать типы указателей, если вы не используете устаревший API ядра, но даже в этом случае вы ограничены одним указателем на часть данных без указателя. https://android.googlesource.com/platform/cts/+/master/tests/tests/renderscript/src/android/renderscript/cts/kernel_all.rs имеет много простых ядер, которые мы используем для тривиального тестирования. Это показывает, как объединить большинство типов.
При желании вы можете включить параметр rs_kernel_context (который позволяет вам искать информацию о размере запуска). Вы также можете при желании передать x, y и / или z (с типом uint32_t каждый), чтобы получить фактические индексы, по которым происходит текущее выполнение. Каждая координата x /y/z будет уникальной для одного запуска, давая вам знать, над какой ячейкой ведется операция.
Для вашего вопроса 4 вы не можете использовать радиус так, как вы хотите. Это должна быть глобальная переменная в качестве входных данных, поскольку наши единственные входные данные ядра традиционно меняются при переходе от ячейки к ячейке распределений ввода / вывода. Вы можете посмотреть https://android.googlesource.com/platform/cts/+/master/tests/tests/renderscript/src/android/renderscript/cts/intrinsic_blur.rs конкретный пример размытия.
Просто некоторые ключевые моменты, с которыми я боролся, когда начал изучать РС. В основном желтые тексты выше включают всю мудрость РС, но в "слишком компактном" виде. Чтобы ответить на ваши вопросы 1 и 2, вы должны различать два типа распределения. Первый тип распределения я называю "формальным" распределением. В выражении ядра
uchar4 __attribute__((kernel)) invert(uchar4 in, uint32_t x, uint32_t y) {
это распределение на входе в (типа uchar4, то есть 8-битное целое число без знака) и распределение на выходе, которое также является uchar4 - это тип, который вы можете видеть в левой части выражения ядра. Вывод - это то, что будет возвращено через "возврат", так же, как в функциях Java. Вам нужно по крайней мере одно формальное распределение (т.е. один вход ИЛИ один выход ИЛИ оба).
Другой тип распределения я называю "боковое распределение". Это то, что вы обрабатываете с помощью глобальных скриптов, и это может быть как распределение ввода, так и вывода. Если вы используете их в качестве входных данных, вы передадите входные данные со стороны Java через copyTo(). Если вы используете их в качестве вывода, вы получите вывод на сторону Java через copyFrom().
Дело в том, что, хотя вам требуется хотя бы одно формальное распределение, качественного различия между формальным и побочным распределением нет, единственное, что вам нужно, это использовать хотя бы одно формальное распределение.
Все выделения в ядре ("формальные" или "боковые") имеют одинаковые размеры с точки зрения ширины и высоты.
На вопрос 3 имплицитно отвечают 1 и 2.
- только формальное распределение ресурсов,
- только формальное распределение,
- как формальное распределение ввода, так и формальное распределение
- 1.-3. каждый может иметь любое количество дополнительных "побочных" распределений.
Вопрос 4: Да. В вашем примере Gauss, если вы хотите передать радиус размытия (например, 1-100) или алгоритм размытия (например, типы 1,2 и 3), вы просто использовали бы одну глобальную переменную для каждого из них, чтобы они могли быть применяется внутри ядра. Здесь я бы не говорил о "распределении" в вышеприведенном смысле, поскольку они всегда имеют одинаковое измерение с сеткой, охватываемой ядром (обычно x ширина умножается на y высоту). Тем не менее, вам все равно нужно передать эти параметры через script_setxxx(гггг).
Надеюсь это немного поможет.