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
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);