RenderScript неправильно манипулирует выводом ядра

Я пытаюсь использовать Android RenderScript для рендеринга полупрозрачного круга за изображением, но при возврате значения из ядра RenderScript все идет очень неправильно.

Это мое ядро:

#pragma version(1)
#pragma rs java_package_name(be.abyx.aurora)
// We don't need very high precision floating points
#pragma rs_fp_relaxed

// Center position of the circle
int centerX = 0;
int centerY = 0;

// Radius of the circle
int radius = 0;

// Destination colour of the background can be set here.
float destinationR;
float destinationG;
float destinationB;
float destinationA;

static int square(int input) {
    return input * input;
}

uchar4 RS_KERNEL circleRender(uchar4 in, uint32_t x, uint32_t y) {
    //Convert input uchar4 to float4
    float4 f4 = rsUnpackColor8888(in);

    // Check if the current coordinates fall inside the circle
    if (square(x - centerX) + square(y - centerY) < square(radius)) {
        // Check if current position is transparent, we then need to add the background!)
        if (f4.a == 0) {
            uchar4 temp = rsPackColorTo8888(0.686f, 0.686f, 0.686f, 0.561f);
            return temp;
        }
    }

    return rsPackColorTo8888(f4);
}

Теперь функция rsPackColorTo8888() принимает 4 числа с плавающей запятой со значением от 0,0 до 1,0. Результирующий цвет ARGB затем находится путем 255-кратного вычисления каждого значения с плавающей запятой. Таким образом, данные поплавки соответствуют цвету R = 0,686 * 255 = 175, G = 0,686 * 255 = 175, B = 0,686 * 255 = 175 и A = 0,561 * 255 = 143.

Сама функция rsPackColorTo8888() работает правильно, но когда из ядра возвращается найденное значение uchar4, происходит что-то очень странное. Значения R, G и B изменяются соответственно на Красный * Альфа = 56, Зеленый * Альфа = 56 и Синий * Альфа = 56, где Альфа равен 0,561. Это означает, что никакое значение R, G и B не может быть больше, чем A = 0,561 * 255.

Установка вывода вручную вместо использования rsPackColorTo8888() дает точно такое же поведение. Я имею в виду, что следующий код дает точно такой же результат, что, в свою очередь, доказывает, что проблема не в rsPackColorTo8888():

if (square(x - centerX) + square(y - centerY) < square(radius)) {
    // Check if current position is transparent, we then need to add the background!)
    if (f4.a == 0) {
        uchar4 temp;
        temp[0] = 175;
        temp[1] = 175;
        temp[2] = 175;
        temp[3] = 143;
        return temp;
    }
}

Это Java-код, из которого вызывается скрипт:

@Override
public Bitmap renderParallel(Bitmap input, int backgroundColour, int padding) {
    ResizeUtility resizeUtility = new ResizeUtility();

    // We want to end up with a square Bitmap with some padding applied to it, so we use the
    // the length of the largest dimension (width or height) as the width of our square.
    int dimension = resizeUtility.getLargestDimension(input.getWidth(), input.getHeight()) + 2 * padding;

    Bitmap output = resizeUtility.createSquareBitmapWithPadding(input, padding);
    output.setHasAlpha(true);

    RenderScript rs = RenderScript.create(this.context);

    Allocation inputAlloc = Allocation.createFromBitmap(rs, output);
    Type t = inputAlloc.getType();

    Allocation outputAlloc = Allocation.createTyped(rs, t);

    ScriptC_circle_render circleRenderer = new ScriptC_circle_render(rs);

    circleRenderer.set_centerX(dimension / 2);
    circleRenderer.set_centerY(dimension / 2);
    circleRenderer.set_radius(dimension / 2);
    circleRenderer.set_destinationA(((float) Color.alpha(backgroundColour)) / 255.0f);
    circleRenderer.set_destinationR(((float) Color.red(backgroundColour)) / 255.0f);
    circleRenderer.set_destinationG(((float) Color.green(backgroundColour)) / 255.0f);
    circleRenderer.set_destinationB(((float) Color.blue(backgroundColour)) / 255.0f);

    circleRenderer.forEach_circleRender(inputAlloc, outputAlloc);
    outputAlloc.copyTo(output);

    inputAlloc.destroy();
    outputAlloc.destroy();
    circleRenderer.destroy();
    rs.destroy();

    return output;
}

Когда для альфа установлено значение 255 (или 1,0 как число с плавающей запятой), возвращаемые значения цвета (внутри Java-кода моего приложения) верны.

Я что-то делаю не так, или это действительно ошибка где-то в реализации RenderScript?

Примечание. Я проверил и подтвердил это поведение на Oneplus 3T (Android 7.1.1), Nexus 5 (Android 7.1.2), Android-эмуляторе версий 7.1.2 и 6.0.


person Community    schedule 30.08.2017    source источник
comment
Можете ли вы поделиться своим кодом Java и на каком устройстве вы тестируете?   -  person sakridge    schedule 31.08.2017
comment
@sakridge Спасибо за ответ! Я добавил Java-код и устройства, которые я использовал для тестирования, в свой пост.   -  person    schedule 02.09.2017
comment
Я не уверен, но, возможно, сравнение fa.a == 0 оценивается как ложное, потому что fa.a является числом с плавающей запятой. Если вы перейдете на in.a == 0, будет ли вывод такой же?   -  person Zamrony P. Juhara    schedule 09.09.2017


Ответы (1)


Вместо того, чтобы передавать значения с типом:

uchar4 temp = rsPackColorTo8888(0.686f, 0.686f, 0.686f, 0.561f);

Попытка создать float4 и передать его.

float4 newFloat4 = { 0.686, 0.686, 0.686, 0.561 };
uchar4 temp = rsPackColorTo8888(newFloat4);
person Community    schedule 09.09.2017