如果发生多个渲染器切换,SDL_SetRenderTarget() 会挂起一段时间

SDL_SetRenderTarget() hangs for a while if multiple renderer switch occurs

打开渲染目标开关时出现问题 Raspberry Pi。如果发生多个渲染器切换,SDL_SetRenderTarget() 挂起。

这是一个工作代码,它在渲染目标切换前后打印自应用程序启动以来的毫秒数:

#include <stdio.h>
#include "SDL.h"


static SDL_Window* gameWindow = NULL;
static SDL_Renderer* windowRenderer = NULL;
static SDL_Texture* gameTexture = NULL;
static SDL_Texture* texture_1 = NULL;
static SDL_Texture* texture_2 = NULL;
static SDL_Texture* texture_3 = NULL;
static SDL_Texture* texture_4 = NULL;
static SDL_Texture* texture_5 = NULL;
static int row;
static int column;


int main()
{
    // Initialize SDL Video
    if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
    {
        printf("%d ms - [INFO] - SDL fails to initialize video subsystem!\n%s", SDL_GetTicks(), SDL_GetError());
        return -1;
    }
    else
        printf("%d ms - [INFO] - SDL Video was initialized fine!\n", SDL_GetTicks());

    // Create window
    gameWindow = SDL_CreateWindow(
                "SDL Render Target Test",
                SDL_WINDOWPOS_CENTERED,
                SDL_WINDOWPOS_CENTERED,
                640,
                480,
                SDL_WINDOW_SHOWN);

    windowRenderer = SDL_CreateRenderer(gameWindow, -1, SDL_RENDERER_ACCELERATED);

    if (windowRenderer == NULL)
        return -1;

    // Set color (this format is RGBA) --> Black, Opaque
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0xff);

    // Clear renderer
    SDL_RenderClear(windowRenderer);

    printf("Window and renderer created!\n");

    gameTexture = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 240);
    texture_1 = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1920, 1080);
    texture_2 = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1920, 1080);
    texture_3 = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1920, 1080);
    texture_4 = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1920, 1080);
    texture_5 = SDL_CreateTexture(windowRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1920, 1080);

    printf("Textures created!\n");

    if (gameTexture == NULL || texture_1 == NULL || texture_2 == NULL || texture_3 == NULL || texture_4 == NULL || texture_5 == NULL)
    {
        SDL_DestroyRenderer(windowRenderer);
        windowRenderer = NULL;

        return -1;
    }

    // Set textures blend mode
    SDL_SetTextureBlendMode(gameTexture, SDL_BLENDMODE_BLEND);
    SDL_SetTextureBlendMode(texture_1, SDL_BLENDMODE_BLEND);
    SDL_SetTextureBlendMode(texture_2, SDL_BLENDMODE_BLEND);
    SDL_SetTextureBlendMode(texture_3, SDL_BLENDMODE_ADD);
    SDL_SetTextureBlendMode(texture_4, SDL_BLENDMODE_BLEND);
    SDL_SetTextureBlendMode(texture_5, SDL_BLENDMODE_MOD);

    printf("Textures blend set!\n");


    // +++ Texture 1 +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_1
    SDL_SetRenderTarget(windowRenderer, texture_1);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    // Set color (this format is RGBA) --> Black, Transparent
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x00);

    // Clear texture_1
    SDL_RenderClear(windowRenderer);

    // Set color (this format is RGBA) --> Black, With some transparency
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x5a); // SDL_BLENDMODE_BLEND

    for (row = 0; row < 1080; row += 4)
        SDL_RenderDrawLine(windowRenderer, 0, row, 1920, row);

    printf("Texture 1 created!\n");


    // +++ Texture 2 +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_2
    SDL_SetRenderTarget(windowRenderer, texture_2);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    for (column = 0; column < 1920; column += 4)
    {
        // SDL_BLENDMODE_BLEND

        // Set color (this format is RGBA)
        SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0xff);
        SDL_RenderDrawLine(windowRenderer, column, 0, column, 1080);

        // Set color (this format is RGBA)
        SDL_SetRenderDrawColor(windowRenderer, 0xff, 0x00, 0x00, 0xff);
        SDL_RenderDrawLine(windowRenderer, column + 1, 0, column + 1, 1080);

        // Set color (this format is RGBA)
        SDL_SetRenderDrawColor(windowRenderer, 0x00, 0xff, 0x00, 0xff);
        SDL_RenderDrawLine(windowRenderer, column + 2, 0, column + 2, 1080);

        // Set color (this format is RGBA)
        SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0xff, 0xff);
        SDL_RenderDrawLine(windowRenderer, column + 3, 0, column + 3, 1080);
    }

    printf("Texture 2 created!\n");


    // +++ Texture 3 for brightness +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_3
    SDL_SetRenderTarget(windowRenderer, texture_3);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    // Set color (this format is RGBA)
    SDL_SetRenderDrawColor(windowRenderer, 0xff, 0xff, 0xff, 0xd0); // SDL_BLENDMODE_ADD

    // Clear texture_3
    SDL_RenderClear(windowRenderer);

    printf("Texture 3 created!\n");


    // +++ Combine textures to texture_5 +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_5
    SDL_SetRenderTarget(windowRenderer, texture_5);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    // Set color (this format is RGBA) --> Black, Opaque
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0xff);

    // Clear texture_5
    SDL_RenderClear(windowRenderer);

    printf("Start texture combination!\n");

    // Render texture_2 to texture_5
    SDL_RenderCopy(windowRenderer, texture_2, NULL, NULL);

    printf("First combination done!\n");

    SDL_DestroyTexture(texture_2);


    // +++ Texture 4 +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_4
    SDL_SetRenderTarget(windowRenderer, texture_4);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    // Set color (this format is RGBA) --> Black, Transparent
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x00);

    // Clear texture_4
    SDL_RenderClear(windowRenderer);

    // Set color (this format is RGBA)
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x15); // SDL_BLENDMODE_BLEND

    for (column = 0; column < 1920; column += 4)
    {
        SDL_RenderDrawLine(windowRenderer, column, 0, column, 1080);
    }

    for (row = 0; row < 1080; row += 4)
    {
        for (column = 1; column < 1920; column += 8)
        {
            SDL_RenderDrawPoint(windowRenderer, column, row);
            SDL_RenderDrawPoint(windowRenderer, column + 1, row);
            SDL_RenderDrawPoint(windowRenderer, column + 2, row);
            SDL_RenderDrawPoint(windowRenderer, column + 3, row);

            SDL_RenderDrawPoint(windowRenderer, column + 4, row + 2);
            SDL_RenderDrawPoint(windowRenderer, column + 4 + 1, row + 2);
            SDL_RenderDrawPoint(windowRenderer, column + 4 + 2, row + 2);
            SDL_RenderDrawPoint(windowRenderer, column + 4 + 3, row + 2);
        }
    }

    printf("Texture 4 created!\n");


    // +++ Combine texture to texture_5 +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on texture_5
    SDL_SetRenderTarget(windowRenderer, texture_5);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    printf("Start texture combination!\n");

    // Render texture_3 to texture_5
    SDL_RenderCopy(windowRenderer, texture_3, NULL, NULL);

    printf("Second combination done!\n");

    SDL_DestroyTexture(texture_3);

    printf("Texture 5 created!\n");


    // +++ Set default rendering target +++ //

    printf("%d ms - [INFO] - Set renderer...\n", SDL_GetTicks());

    // Set target for drawing operation on default rendering target
    SDL_SetRenderTarget(windowRenderer, NULL);

    printf("%d ms - [INFO] - Renderer set!\n", SDL_GetTicks());

    // Set color (this format is RGBA) --> Black, Transparent
    SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x00);

    // Clear default renderer
    SDL_RenderClear(windowRenderer);

    SDL_DestroyTexture(texture_1);
    SDL_DestroyTexture(texture_4);
    SDL_DestroyTexture(texture_5);

    SDL_DestroyRenderer(windowRenderer);

    SDL_DestroyWindow(gameWindow);

    return 0;
}

这是 Ubuntu x86 上的输出:

108 ms - [INFO] - SDL Video was initialized fine!
Window and renderer created!
Textures created!
Textures blend set!
252 ms - [INFO] - Set renderer...
253 ms - [INFO] - Renderer set!
Texture 1 created!
253 ms - [INFO] - Set renderer...
254 ms - [INFO] - Renderer set!
Texture 2 created!
255 ms - [INFO] - Set renderer...
257 ms - [INFO] - Renderer set!
Texture 3 created!
257 ms - [INFO] - Set renderer...
257 ms - [INFO] - Renderer set!
Start texture combination!
First combination done!
258 ms - [INFO] - Set renderer...
258 ms - [INFO] - Renderer set!
Texture 4 created!
375 ms - [INFO] - Set renderer...
450 ms - [INFO] - Renderer set!
Start texture combination!
Second combination done!
Texture 5 created!
450 ms - [INFO] - Set renderer...
450 ms - [INFO] - Renderer set!

这是 Raspberry Pi 的结果:

94 ms - [INFO] - SDL Video was initialized fine!
Window and renderer created!
Textures created!
Textures blend set!
242 ms - [INFO] - Set renderer...
242 ms - [INFO] - Renderer set!
Texture 1 created!
243 ms - [INFO] - Set renderer...
286 ms - [INFO] - Renderer set!
Texture 2 created!
288 ms - [INFO] - Set renderer...
386 ms - [INFO] - Renderer set!
Texture 3 created!
386 ms - [INFO] - Set renderer...
386 ms - [INFO] - Renderer set!
Start texture combination!
First combination done!
396 ms - [INFO] - Set renderer...
415 ms - [INFO] - Renderer set!
Texture 4 created!
837 ms - [INFO] - Set renderer...
24786 ms - [INFO] - Renderer set!
Start texture combination!
Second combination done!
Texture 5 created!
24787 ms - [INFO] - Set renderer...
24787 ms - [INFO] - Renderer set!

应用程序挂起 23 秒!!!任何的想法?同样在 Ubuntu x86 上,在消息 Texture 4 created! rendering set

之后速度变慢

进一步调查发现问题出在SDL_RenderDrawPoint()的使用上。如果我们在代码开头移动纹理 4 创建,则在该纹理创建之后会发生减速,因此在大量使用 SDL_RenderDrawPoint().

之后

我解决了从 SDL_RenderDrawPoint()SDL_RenderDrawPoints().

在我的例子中没关系,因为纹理只在启动时创建一次,这样我们就从 23 秒减少到 200 毫秒