SDL2 - странное снижение производительности при быстром изменении цвета - PullRequest
3 голосов
/ 06 ноября 2019

Я был удивлен, когда узнал об этом, сначала я подумал, что что-то не так с моими алгоритмами, но после более тщательной проверки я обнаружил, что чем больше вы меняете цвета, тем больше это влияет на производительность. Почему это?

Вот (все) код:

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

Вот производительность с этим кодом:

enter image description here

А вот производительность с этим кодом:

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

enter image description here

AsВы можете видеть, что при значительном изменении цвета производительность сильно влияет. На самом деле это становится в 100 раз медленнее. Что я делаю неправильно? Или это так должно работать?

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Очевидно, что функция SDL_SetRenderDrawColor занимает некоторое время, чтобы выполнить и изменить цвета. Может быть, даже данные о цвете нужно отправлять в графический процессор, который очень медленный по сравнению с обычным доступом к памяти. Также функция rand требует некоторой производительности.

При использовании ваших данных разница между SDL_SetRenderDrawColor и 10000 составляет примерно 550ms. Таким образом, каждый вызов этой функции стоит около 55µs. Это очень крошечный и вызов нескольких десятков раз не сильно влияет на производительность, но 10000 вызовов, очевидно, намного больше.

Если вы согласны, что один вызов передает 4 байта в GPU, вы передаете 40 КБуже только для цветов.

0 голосов
/ 06 ноября 2019

Я спросил парня (Gorbit99), который знает кое-что о SDL, и он сказал мне, что проблема заключается в использовании текстур и SDL_SetRenderDrawColor, который работает на графическом процессоре, но взаимодействие на пиксель быстрее на процессоре, поэтомувместо SDL_Texture вы используете SDL_Surface. А теперь это мой окончательный код (производительность ~ 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);
...