问题 在Renderscript Compute中将数组传递给rsForEach


我发现在RenderScript中缺少良好的文档,据我所知, forEach 在RS中是为分配中的每个单独项执行root()。

我正在尝试为Renderscript创建一个图像处理库,作为一个起点,我达到了这一点 很好的答案。但问题是,模糊操作是打开的  像素和每个像素需要另一个循环(n具有模糊宽度)的计算。尽管在多核上运行,但它仍然有点太慢。

我试图修改它以允许(两次通过)盒式过滤器,但这需要处理单个行或列而不是单元格。那么,有没有办法让foreach将数组发送到root()?


4810
2018-05-14 01:23


起源

您可以使用2个脚本进行水平和垂直模糊。 stackoverflow.com/questions/13435561/... - Sid Datta


答案:


rsForEach只能在分配时运行。

如果你想让rsForEach函数为每个图像行调用root(),你必须在一个Allocation中传递一个大小与行数相同的长度,然后找出你应该在哪个行上操作root()(类似于在每列上操作)。然后,RenderScript应该将工作分配给可用资源(在多核设备上同时处理多个行)。

您可以这样做的一种方法是传入一个Allocation,它给出图像行的偏移量(在图像数据数组中)。然后,根()内的v_in参数将是行偏移量。由于操作的rsForEach调用的分配不是图像数据,因此无法使用v_out参数写出图像,并且必须单独绑定输出图像。

以下是一些显示此内容的RenderScript:

#pragma version(1)
#pragma rs java_package_name(com.android.example.hellocompute)

rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

int mImageWidth;
const uchar4 *gInPixels;
uchar4 *gOutPixels;

void init() {
}

static const int kBlurWidth = 20;

//
// This is called per row.
// The row indices are passed in as v_in or you could also use the x argument and multiply it by image width.
//
void root(const int32_t *v_in, int32_t *v_out, const void *usrData, uint32_t x, uint32_t y) {
    float3 blur[kBlurWidth];
    float3 cur_colour = {0.0f, 0.0f, 0.0f};

    for ( int i = 0; i < kBlurWidth; i++) {
        float3 init_colour = {0.0f, 0.0f, 0.0f};
        blur[i] = init_colour;
    }

    int32_t row_index = *v_in;
    int blur_index = 0;

    for ( int i = 0; i < mImageWidth; i++) {
        float4 pixel_colour = rsUnpackColor8888(gInPixels[i + row_index]);

        cur_colour -= blur[blur_index];
        blur[blur_index] = pixel_colour.rgb;
        cur_colour += blur[blur_index];

        blur_index += 1;
        if ( blur_index >= kBlurWidth) {
            blur_index = 0;
        }

        gOutPixels[i + row_index] = rsPackColorTo8888(cur_colour/(float)kBlurWidth);
        //gOutPixels[i + row_index] = rsPackColorTo8888(pixel_colour);
    }
}


void filter() {
    rsDebug("Number of rows:", rsAllocationGetDimX(gIn));
    rsForEach(gScript, gIn, gOut, NULL);
}

这将使用以下Java设置:

    mBlurRowScript = new ScriptC_blur_row(mRS, getResources(), R.raw.blur_row);

    int row_width = mBitmapIn.getWidth();

    //
    // Create an allocation that indexes each row.
    //
    int num_rows = mBitmapIn.getHeight();
    int[] row_indices = new int[num_rows];
    for ( int i = 0; i < num_rows; i++) {
        row_indices[i] = i * row_width;
    }
    Allocation row_indices_alloc = Allocation.createSized( mRS, Element.I32(mRS), num_rows, Allocation.USAGE_SCRIPT);
    row_indices_alloc.copyFrom(row_indices);

    //
    // The image data has to be bound to the pointers within the RenderScript so it can be accessed
    // from the root() function.
    //
    mBlurRowScript.bind_gInPixels(mInAllocation);
    mBlurRowScript.bind_gOutPixels(mOutAllocation);

    // Pass in the image width
    mBlurRowScript.set_mImageWidth(row_width);

    //
    // Pass in the row indices Allocation as the input. It is also passed in as the output though the output is not used.
    //
    mBlurRowScript.set_gIn(row_indices_alloc);
    mBlurRowScript.set_gOut(row_indices_alloc);
    mBlurRowScript.set_gScript(mBlurRowScript);
    mBlurRowScript.invoke_filter();

16
2018-05-16 11:00



+100这是如此聪明,从没想过传递“指数”来伪造它。 - xandy
对于这个脚本,我一直得到“没有用于调用'rsForEach'的匹配函数”。怎么来的?错误的下一行是:“......注意:候选函数不可行:需要3个参数,但提供了4个...注意:候选函数不可行:需要5个参数,但提供了4个...注意:候选函数不可行:需要6个参数,但提供了4个“ - android developer
此方法不再起作用,因为“API 20+仅允许简单的1D分配与bind一起使用”(来自错误消息的引用)。因此mBlurRowScript.bind_gInPixels(mInAllocation);失败。 - Searles
任何人都可以解释我们如何在内核中获取* v_in中的行索引?如果我想传递列索引,我该怎么做? - Sandecoder