从循环

时间:2015-12-10 15:02:58

标签: c optimization switch-statement function-pointers

我有一个名为blend_pixels()的函数,其任务是根据指定的混合模式将单个像素混合到另一个像素上。几乎所有想要绘制任何东西的函数都会调用该函数。

问题是每个像素调用函数,这意味着它每秒被调用数千万次,它包含一个switch-case语句,通过所有可能的混合模式,直到找到正确的之一。

显然,这比调用直接执行所需操作的函数要慢一些,这就是我试图解决的问题。调用blend_pixels()的父函数通常只调用它们自己作为参数调用的混合模式,因此我不能将它们称为只能执行一种混合模式的小函数。但是对于父函数的每次调用只需要做一次选择(父函数在每次调用时对很多像素进行操作,而对于每个像素调用blend_pixels(),在循环中遍历所有必需的像素)。

该功能如下所示:

void blend_pixels(lrgb_t *bg, lrgb_t fg, int32_t p, const int mode)
{
    int32_t r, g, b;

    switch (mode)
    {
        case SOLID:
            *bg = fg;
            break;

        case ADD:
            r = (fg.r * p >> 15) + bg->r;   if (r>ONE) bg->r = ONE; else bg->r = r;
            g = (fg.g * p >> 15) + bg->g;   if (g>ONE) bg->g = ONE; else bg->g = g;
            b = (fg.b * p >> 15) + bg->b;   if (b>ONE) bg->b = ONE; else bg->b = b;
            break;

        case SUB:
            r = -(fg.r * p >> 15) + bg->r;  if (r<0) bg->r = 0; else bg->r = r;
            g = -(fg.g * p >> 15) + bg->g;  if (g<0) bg->g = 0; else bg->g = g;
            b = -(fg.b * p >> 15) + bg->b;  if (b<0) bg->b = 0; else bg->b = b;
            break;

        case MUL:
            ... // you get the idea
    }
}

以这种方式调用:

void parent_function(lrgb_t *fb, int w, int h, lrgb_t colour, ... int blendingmode)
{
    ...
    for (iy=y0; iy<y1; iy++)
        for (ix=x0; ix<x1; ix++)
        {
            p = some_weighting_formula();

            blend_pixels(&fb[iy*w+ix], colour, p, blendingmode);
        }
}

本身可能被称为:

parent_function(fb, w, h, orange, ... /*whatever*/, ADD);

&#34; ADD&#34;是枚举的整数

很明显,选择混合算法的任何开关案例都应该在parent_function的循环之外完成。但是如何?

2 个答案:

答案 0 :(得分:3)

您可以使用函数指针执行此操作。

首先为函数指针定义一个typedef:

typedef void (*blend_function)(lrgb_t *, lrgb_t, int32_t);

然后将blend_pixels的每个部分分解为它自己的函数,每个函数都具有相同的参数并返回类型为typedef:

void blend_pixels_add(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_sub(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_mult(lrgb_t *bg, lrgb_t fg, int32_t p)
...

然后在父函数中,您可以指定函数指针类型的变量,并为其指定要使用的函数的地址:

void parent_function(lrgb_t *fb, int w, int h, lrgb_t colour, ... int blendingmode)
{
    ...
    blend_function blend;
    switch (blendingmode)
    {
        case ADD:
            blend = blend_pixels_add;
            break;
        case SUB:
            blend = blend_pixels_sub;
            break;
        ...
    }
    for (iy=y0; iy<y1; iy++)
        for (ix=x0; ix<x1; ix++)
        {
            p = some_weighting_formula();

            blend(&fb[iy*w+ix], colour, p);
        }
}

答案 1 :(得分:0)

解决您的问题&#34;并且它包含一个切换案例语句,通过所有可能的混合模式,直到找到正确的混合模式。&#34;,这可能不是真正发生的事情。

Switch语句通常被编译成所谓的跳转表。在跳转表中,代码不会遍历所有寻找正确的情况的情况,而是将switch()语句的参数用作地址数组中的索引。类似的东西:

jump_table[SOLID] -> case SOLID address
jump_table[ADD] -> case ADD address
...

因此,在这种实现中,一个正在考虑很多很多值的switch语句应该和手工编码的函数指针解决方案一样快,因为这基本上就是编译器构建的。