В RenderScript мои ядра должны вызываться друг за другом - синхронно. Поскольку это конвейер, а второе ядро зависит от первого, оно ведет к некорректному поведению, если не ожидает окончания работы первого ядра.
Вход и выход первого ядра не имеют одинаковых измеренийпоэтому вывод первого ядра устанавливается с использованием rsAtomicInc()
.
Базовый конвейер таков:
- первое ядро: 2 битовых массива в качестве ввода, массив 1D int в качестве вывода
- второе ядро: массив 1D int в качестве вывода, массив 1D float в качестве входных данных
Kotlin:
nextBitmapAlloc.copyFrom(nextBitmap)
previousBitmapAlloc.copyFrom(previousBitmap)
script.forEach_resetUintArray(horizontalShiftAlloc)
script.forEach_calculateVerticalShift(nextBitmapAlloc)
// Should wait for kernel to finish
script.forEach_normalizeVerticalShift(verticalShiftAlloc, verticalShiftFloatAlloc)
script.invoke_findMax()
val result = IntArray(1).apply { resultAlloc.copyTo(this) }
RenderScript
rs_allocation previousBitmap;
// Results
uint* verticalShiftArray;
float* verticalShiftFloatArray;
uint RS_KERNEL resetUintArray() {
return 0;
}
void RS_KERNEL calculateVerticalShift(uchar4 currentInput, uint x, uint y) {
uint shift;
uint previousY;
uchar4 previousInput = rsGetElementAt_uchar4(previousBitmap, x, previousY);
if (someComparisonLogic(previousInput, currentInput)) {
rsAtomicInc(&verticalShiftArray[shift + height]);
}
}
float RS_KERNEL normalizeHorizontalShift(uint input, uint x) {
uint divider = divider();
return (float) input / (float) divider;
}
void findMax() {
float maxValue = mimumMatchRatioThreshold;
int maxI = -1;
for (int i = 0; i < max; i++) {
float value = verticalShiftArray[i];
if (value > maxValue) {
maxValue = value;
maxI = i;
}
}
rsSetElementAt_int(result, maxI, 0);
}
Полный конвейер вызывается как можно чаще. Иногда result[0]
показывает предыдущий результат. Когда эти строки вызываются снова, возвращается правильный результат:
script.forEach_normalizeVerticalShift(verticalShiftAlloc, verticalShiftFloatAlloc)
script.invoke_findMax()
val result = IntArray(1).apply { resultAlloc.copyTo(this) }
Так что по какой-то причине результат функции forEach_calculateVerticalShift
, который должен находиться в распределении verticalShiftAlloc
, еще не готов. Вызов renderscript.finish
и / или dummyIntArray.apply { verticalShiftAlloc.copyTo(this) }
между первым и вторым ядром помогает часто, но не всегда. Это не кажется более точным, чем прямо с использованием System.sleep()
между ними.
Копирование verticalShiftAlloc
, и расследовать это не помогает;он всегда показывает последние данные, даже когда val result
показывает предыдущий результат.
Как мне дождаться завершения forEach_calculateVerticalShift
, поэтому verticalShiftAlloc
содержит последние результаты?
Замечания
- Для удобства чтения я удалил то, что мне показалось неважным, и заменил его на фиктивные константы и функции. Если это было сделано слишком строго, я могу добавить больше.
- Я выписал Вызов функции блокировки RenderScript и Renderscript rs.finish (), alloc.syncAll (), copyTo (): дождаться завершения выполнения ядра , ноэто мне еще не помогло.