Search code examples
craspberry-pisdl-2

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


There is a problem with rendering target switch on Raspberry Pi. SDL_SetRenderTarget() hangs if multiple renderer switch occurs.

This is a working code that prints milliseconds since application starts before and after a rendering target switch:

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

This is the ouptut on 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!

and this one is the result on 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!

The application hangs for 23 seconds!!! Any idea? Also on Ubuntu x86 there is a slowdown after message Texture 4 created! during rendering set


Solution

  • After further investigation I found that the problem is the use of SDL_RenderDrawPoint(). If we move Texture 4 creation at the beginning of the code the slowdown occurs after that texture creation, so after a massive use of SDL_RenderDrawPoint().

    I fixed the problem passing from SDL_RenderDrawPoint() to SDL_RenderDrawPoints().

    In my case it is ok because that texture is created only one time at startup and in this way we pass from 23 seconds to 200 milliseconds