SDL2 - 快速改变颜色时的奇怪性能下降

3

当我发现这一点时,感到非常惊讶。起初我以为我的算法出了问题,但更仔细地检查后发现,颜色变化越大,对性能的影响就越大。为什么呢?

以下是(全部)代码:

#include <iostream>
#include <SDL2/SDL.h>

const int WIDTH = 1024;
const int HEIGHT = 768;

int main(int argc, char *argv[])
{
    SDL_Window *window;
    SDL_Renderer *renderer;
    SDL_Texture *texture;
    SDL_Event event;

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
        return 3;
    }

    window = SDL_CreateWindow("SDL_CreateTexture",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              1024, 768,
                              SDL_WINDOW_RESIZABLE);

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, WIDTH, HEIGHT);

    bool alive = true;
    while (alive)
    {
        while(SDL_PollEvent(&event) > 0)
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    alive = false;
                break;
            }
        }

        const Uint64 start = SDL_GetPerformanceCounter();

        SDL_SetRenderTarget(renderer, texture);
        SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
        SDL_RenderClear(renderer);

        for(int i = 0; i < 10000; ++i)
        {
            SDL_SetRenderDrawColor(renderer, rand() % 255, rand() % 255, rand() % 255, 255);
            SDL_RenderDrawPoint(renderer, rand() % WIDTH, rand() % HEIGHT);
        }



        SDL_SetRenderTarget(renderer, NULL);
        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);


        const Uint64 end = SDL_GetPerformanceCounter();
        const static Uint64 freq = SDL_GetPerformanceFrequency();
        const double seconds = ( end - start ) / static_cast< double >( freq );
        std::cout << "Frame time: " << seconds * 1000.0 << "ms" << std::endl;
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

问题出在这段代码中:
for(int i = 0; i < 10000; ++i)
{
    SDL_SetRenderDrawColor(renderer, rand() % 255, rand() % 255, rand() % 255, 255);
    SDL_RenderDrawPoint(renderer, rand() % WIDTH, rand() % HEIGHT);
}

使用此代码的性能如下:

输入图像描述

使用此代码的性能如下:

SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
for(int i = 0; i < 10000; ++i)
{
    SDL_RenderDrawPoint(renderer, rand() % WIDTH, rand() % HEIGHT);
}

如您所见,当颜色变化时,性能会受到相当大的影响。实际上,速度会变慢100多倍。

我做错了什么?还是这就是它的正常工作方式?

enter image description here


C和C++是不同的编程语言。看到你使用了std::cout,似乎你正在使用C++而不是C。 - François Andrieux
3
调用rand()函数生成更多的颜色可能会产生影响。 - François Andrieux
考虑使用C++11随机数生成特性代替rand()。虽然rand()对于简单的测试用例来说还可以,但在实践中它存在许多问题(其中一些列在这里)。 - François Andrieux
问题在于SDL_Texture在GPU上工作,而我正在迭代像素。逐个像素地工作更适合CPU,因此您必须使用SDL_Surface。(请参见我的答案)。 - Marat Isaw
显示剩余3条评论
2个回答

0
显然,SDL_SetRenderDrawColor 函数需要一些时间来执行和更改颜色。也许颜色数据甚至必须发送到GPU,这与常规内存访问相比非常缓慢。此外,rand函数也会消耗一些性能。
使用您的数据,单次调用 SDL_SetRenderDrawColor 和10000次之间有约550毫秒的差异。因此,每次调用此函数的成本约为55微秒。这很小,调用几十次并不会对性能产生影响,但是调用10000次显然会导致更大的问题。
如果您同意一次调用向GPU传输4个字节,则仅用于颜色传输就已经传输了40KB。

-1
我问了一个懂得SDL的人(Gorbit99),他告诉我问题出在使用纹理和SDL_SetRenderDrawColor上,这个函数是在GPU上运行的,但每像素交互在CPU上更快,所以你可以使用SDL_Surface代替SDL_Texture。现在这是我的最终代码(性能约为2毫秒)。
SDL_Surface surface = SDL_CreateRGBSurfaceWithFormat(0, WIDTH, HEIGHT, 32, SDL_PIXELFORMAT_ABGR32);
surface = SDL_CreateRGBSurfaceWithFormat(0, WIDTH, HEIGHT, 32, SDL_PIXELFORMAT_ABGR32);
uint32_t* colors = (uint32_t*)surface->pixels;

for( unsigned int i = 0; i < 1000; i++ )
{
    int x = rand() % WIDTH;
    int y = rand() % HEIGHT;

    int offset = ( WIDTH * y ) + x;
    colors[ offset ] = 0x00ff00ff; // 0xrrggbbaa
}

SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);

SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);

SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);

抱歉,但这样说“GPU非常慢,所以我们将使用CPU”,这是不正确的。分批处理会大量占用CPU,而GPU则因没有要执行的命令而饥饿。例如,使用OpenGL和颜色数组可以更快地进行操作,但即使您决定坚持使用纹理,请创建动态纹理并锁定其进行更新,而不是每帧重新创建它。 - keltar
我并不是一般意义上说 CPU 比 GPU 更快。我的意思是,在处理像素精度访问时,CPU 更快。但你对于纹理锁定的想法是正确的。 - Marat Isaw
感谢您的负评,因为这正是我预期的工作方式。 - Marat Isaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接