修改uint8_t数组中的数据非常慢?

时间:2013-05-06 10:47:14

标签: c++ c x86 arm

我目前正在尝试优化我的代码以更快地运行。目前大约需要30ms来更新大约3776000字节。如果我删除了我的函数中的outPx更新,它将在大约3毫秒运行,这意味着outPx的更新正在使函数变慢。

非常感谢任何有关如何提高我的功能速度的潜在反馈。

uint8_t* outPx = (uint8_t*)out.data;
for (int px=0; px<pxSize; px+=4)
    {
        newTopAlpha = (alpha*inPx[px+3]);

        if (0xff == newTopAlpha)
        {
            // top is opaque covers entire bottom

            // set copy over BGR colors
            outPx[px] = inPx[px];
            outPx[px+1] = inPx[px+1];
            outPx[px+2] = inPx[px+2];
            outPx[px+3] = 0xff; //Fully opaque
        }
        else if (0x00 != newTopAlpha)
        {
            // top is not completely transparent
            topAlpha = newTopAlpha/(float)0xff;
            bottomAlpha = outPx[px+3]/(float)0xff;
            newAlpha = topAlpha + bottomAlpha*(1-topAlpha);
            alphaChange = bottomAlpha*(1-topAlpha);

            outPx[px] = (uint8_t)((inPx[px]*topAlpha + outPx[px]*alphaChange)/newAlpha);
            outPx[px+1] = (uint8_t)((inPx[px+1]*topAlpha + outPx[px+1]*alphaChange)/newAlpha);
            outPx[px+2] = (uint8_t)((inPx[px+2]*topAlpha + outPx[px+2]*alphaChange)/newAlpha);
            outPx[px+3] = (uint8_t)(newAlpha*0xff);
        }
    }

3 个答案:

答案 0 :(得分:2)

您的代码正在执行浮点除法,并且从字节转换为浮点数并再次返回。如果使用整数数学,则很可能更有效。

即使这样简单的转换乘法而不是除法也可能有所帮助:

newAlpha = 1/(topAlpha + bottomAlpha*(1-topAlpha)); 

... 

outpx = (uint8_t)((inPx[px]*topAlpha + outPx[px]*alphaChange)*newAlpha);

乘法往往比分裂快得多。

答案 1 :(得分:1)

uint8_t精确宽度整数类型,这意味着您要求编译器为您的类型准确分配那么多内存。如果您的系统具有对齐要求,则可能导致代码运行速度变慢。

uint8_t更改为uint_fast8_t。这告诉编译器如果可能的话,你希望这个变量是8位,但是如果它使代码更快就可以使用更大的大小。

除此之外,还有许多可能导致性能不佳的事情,在这种情况下,您需要说明您正在使用的系统和编译器。

答案 2 :(得分:0)

好吧,如果这确实是瓶颈,并且由于某些随机原因你无法使用GPU /内置方法,那么你可以做很多事情:

uint8_t *outPx = (uint8_t*) out.data;
const int cAlpha = (int) (alpha * 256.0f + 0.5f);
for( int px = 0; px < pxSize; px += 4 ) {
    const int topAlpha = (cAlpha * (int) inPx[px|3]) >> 8; // note | not + for tiny speed boost

    if( topAlpha == 255 ) {
        memcpy( &outPx[px], &inPx[px], 4 ); // might be slower than per-component copying; benchmark!
    } else if( topAlpha ) {
        const int bottomAlpha = (int) outPx[px|3];
        const int alphaChange = (bottomAlpha * (255 - topAlpha)) / 255;
        const int newAlpha    = topAlpha + alphaChange;

        outPx[px  ] = (uint8_t) ((inPx[px  ]*topAlpha + outPx[px  ]*alphaChange) / newAlpha);
        outPx[px|1] = (uint8_t) ((inPx[px|1]*topAlpha + outPx[px|1]*alphaChange) / newAlpha);
        outPx[px|2] = (uint8_t) ((inPx[px|2]*topAlpha + outPx[px|2]*alphaChange) / newAlpha);
        outPx[px|3] = (uint8_t) newAlpha;
    }
}

主要的变化是不再有浮点运算(我可能错过了/255或其他东西,但你明白了。)我还删除了重复计算并尽可能使用了位运算符。另一个优化是使用固定精度算术将3个除法变为单个除法和3个乘法/位移位。但你必须进行基准测试以确认实际上有所帮助。 memcpy 可能更快。同样,您需要进行基准测试。

最后,如果您对图像有所了解,可以给编译器提供有关分支的提示。例如,在GCC中,如果您知道大部分图像是纯色,并且if( __builtin_expect( topAlpha == 255, 1 ) )是1.0,则可以说alpha


根据评论更新:

对于对理智的热爱,永远不会从不)基准优化关闭。