Второе ядро ​​RenderScript должно ждать на выходе первого ядра - PullRequest
0 голосов
/ 14 октября 2019

В 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 содержит последние результаты?

Замечания

  1. Для удобства чтения я удалил то, что мне показалось неважным, и заменил его на фиктивные константы и функции. Если это было сделано слишком строго, я могу добавить больше.
  2. Я выписал Вызов функции блокировки RenderScript и Renderscript rs.finish (), alloc.syncAll (), copyTo (): дождаться завершения выполнения ядра , ноэто мне еще не помогло.
...