I think SDL_ttf is disturbing SDL_SetRenderDrawColor for me

I have a problem I using SDL in Visual Studio 2019. It is a new problem I did not have 2 week ago. I can’t tell exactly when it appeared because I have updated VS2019, Windows, my Nvidia driver since I last compiled SDL in VS. This have worked as I expected in the past, it is just recently it started to happen.

The problem is that when I print text the color when I draw simple shaped like SDL_RenderFillRect is disturbed. I run the code below and the verry first frame it works as intende then all rectangles and lines turn black.

/*Current NuGet packets installed

Install-Package sdl2.nuget -Version 2.0.10
Install-Package sdl2_image.nuget -Version 2.0.5
Install-Package sdl2_ttf.nuget -Version 2.0.15
Install-Package sdl2_mixer.nuget -Version 2.0.4
*/

#include <iostream>
#include <string>
#include <assert.h>

#include <SDL.h>
#include <SDL_ttf.h>

void DrawText(SDL_Renderer *renderer, TTF_Font *amiga, std::string text, SDL_Color color, int x, int y)
{
    SDL_Surface *surface;
    SDL_Texture *texture;

    surface = TTF_RenderText_Solid(amiga, text.c_str(), color);
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_Rect dest;
    int w;
    int h;
    SDL_QueryTexture(texture, NULL, NULL, &w, &h);
    dest.x = x;
    dest.y = y;
    dest.w = w;
    dest.h = h;

    SDL_RenderCopy(renderer, texture, NULL, &dest);
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(surface);
}

int main(int argc, char *argv[])
{
    std::cout << "enter" << std::endl;

    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();

    SDL_Window *window = SDL_CreateWindow("A bug?", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 768, SDL_WINDOW_SHOWN);
    assert(window);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
    assert(renderer);
    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
    TTF_Font *amiga = TTF_OpenFont("amiga4ever pro2.ttf", 16);;
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    for(int i = 0; i < 5; i++)
    {
        SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
        SDL_RenderClear(renderer);

        SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
        SDL_RenderDrawLine(renderer, 10, 10, 900, 600);

        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
        SDL_Rect dest;
        dest.x = 100;
        dest.y = 100;
        dest.h = 100;
        dest.w = 100;
        SDL_RenderFillRect(renderer, &dest);

        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
        dest;
        dest.x = 200;
        dest.y = 200;
        dest.h = 100;
        dest.w = 100;
        SDL_RenderFillRect(renderer, &dest);

        DrawText(renderer, amiga, "white text", { 255, 255, 255, 255 }, 40, 500);

        SDL_RenderPresent(renderer);
        SDL_Delay(2000); // 2 second delay show the error
    }

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

    std::cout << "exit" << std::endl;
    system("pause");
    return 0;
}

This is the very first frame of the program. I used a sleep for 2 seconds between frames to make it easy to spot for me.

Then every frame after that looks like this. It is after I print text that the color of the rectangles and line changes to what I do not expect.

I got two computers both running Windows 10, VS2019, and got Nvidia graphics cards. And both have the same problem. I even tried downgrading SDL to 2.0.9 but the same problem occur.

I tried it on my work computer today and it had the same problem. Am I doing something wrong or is it a new bug?

I tried running your code and the output I got is rather something I had expected - everything looks the same as you describe it, so I guess it’s not a matter of your system.
Try using TTF_RenderText_Blended instead of
TTF_RenderText_Solid - works fine for me.

It could be because of SDL_Create/DestroyTexture before SDL_RenderPresent occurs, from your draw_text().
I would move the draw texture after render present.

This may be also something solved in latest head SDL sources

TTF_RenderText_Solid works when I only use white text. But when I add more text in different colors it starts to act up again.

It works when I comment out SDL_DestroyTexture(texture); and SDL_FreeSurface(surface); in DrawText()

Should I report it as a bug again or is SDL_ttf 2.0.16 already incoming soon?

This isn’t an issue with SDL_ttf but rather in SDL.
I think this should be fixed in latest head sources. Please double-check using latest SDL sources !

I am using the latest version nuget can give me in Visual Studio. Which is Install-Package sdl2.nuget -Version 2.0.10 and Install-Package sdl2_ttf.nuget -Version 2.0.15.

The more I think about it the more I believe this started to happen after a Windows 10 update. Can anyone who run gnu/Linux check if the same thing happen for them?

Ps: when I destroy the temporary surface and texture for drawing texts after rendering it works fine. Like this;

/*Current NuGet packets installed

Install-Package sdl2.nuget -Version 2.0.10
Install-Package sdl2_ttf.nuget -Version 2.0.15
Install-Package sdl2_image.nuget -Version 2.0.5
Install-Package sdl2_mixer.nuget -Version 2.0.4
*/

#include <iostream>
#include <string>
#include <vector>
#include <assert.h>

#include <SDL.h>
#include <SDL_ttf.h>

struct ToDestroy
{
    SDL_Surface *surface;
    SDL_Texture *texture;
};

std::vector<ToDestroy> garbage;

void DrawText(SDL_Renderer *renderer, TTF_Font *amiga, std::string text, SDL_Color color, int x, int y)
{
    SDL_Surface *surface;
    SDL_Texture *texture;

    //surface = TTF_RenderText_Solid(amiga, text.c_str(), color);
    //surface = TTF_RenderText_Blended(amiga, text.c_str(), color);
    surface = TTF_RenderText_Blended_Wrapped(amiga, text.c_str(), color, 1000);
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_Rect dest;
    int w;
    int h;
    SDL_QueryTexture(texture, NULL, NULL, &w, &h);
    dest.x = x;
    dest.y = y;
    dest.w = w;
    dest.h = h;

    SDL_RenderCopy(renderer, texture, NULL, &dest);


    //SDL_DestroyTexture(texture);
    //SDL_FreeSurface(surface); 
    ToDestroy a;
    a.surface = surface;
    a.texture = texture;
    garbage.push_back(a);

}

int main(int argc, char *argv[])
{
    std::cout << "enter" << std::endl;

    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();

    SDL_Window *window = SDL_CreateWindow("A bug?", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 768, SDL_WINDOW_SHOWN);
    assert(window);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
    assert(renderer);
    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
    TTF_Font *amiga = TTF_OpenFont("amiga4ever pro2.ttf", 16);;
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    for(int i = 0; i < 5; i++)
    //while(true)
    {
        //SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
        //SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        DrawText(renderer, amiga, "Green text", { 0, 255, 0, 255 }, 40, 10);
        DrawText(renderer, amiga, "Red text", { 255, 0, 0, 255 }, 40, 50);

        //DrawText(renderer, amiga, "white text", { 255, 255, 255, 255 }, 40, 400);

        SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
        SDL_RenderDrawLine(renderer, 10, 10, 900, 600);

        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
        SDL_Rect dest;dest.x = 100;dest.y = 100;dest.h = 100;dest.w = 100;
        SDL_RenderFillRect(renderer, &dest);

        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
        dest.x += 100;dest.y += 100;dest.h = 100;dest.w = 100;
        SDL_RenderFillRect(renderer, &dest);
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        dest.x += 100; dest.y += 100; dest.h = 100; dest.w = 100;
        SDL_RenderFillRect(renderer, &dest);


        //DrawText(renderer, amiga, "black text", { 0, 0, 0, 255 }, 40, 400);
        DrawText(renderer, amiga, "Blue text", { 0, 0, 255, 255 }, 40, 450);
        DrawText(renderer, amiga, "white text", { 255, 255, 255, 255 }, 40, 500);

        SDL_RenderPresent(renderer);
        for(auto &g: garbage)
        {
            SDL_DestroyTexture(g.texture);
            SDL_FreeSurface(g.surface);
        }
        garbage.clear();
        SDL_Delay(2000); // 2 second delay show the error

    }

    system("pause");
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    TTF_CloseFont(amiga);
    SDL_Quit();

    std::cout << "exit" << std::endl;
    return 0;
}

PPs. I will try to build SDL from source myself for the first time later this weekend.

Hey. I just came here to report almost the exact same bug. I’m on a Linux box, cross-compiling with mingw32 and testing under 64-bit Wine. The bug still occurs.

From my tests, this happens when creating text using either TTF_RenderUTF8_Solid() or TTF_RenderUTF8_Blended(), transferring the surface to a texture, calling SDL_RenderCopy() and then SDL_DestroyTexture(). After that, the color of the text is getting blended into the render draw color, and cannot be easily removed. How it gets blended depends on which TTF function was used, though if you don’t use colors that blend well, the result will almost always be black or near-black.

I’ve also verified that bypassing any of the aforementioned API calls (e.g. SDL_DestroyTexture()) prevents the bug from manifesting.

Is there an actual bug filed about this? It would really help me to be able to track when a fixed version of SDL is released!

1 Like

(Oh, and just to be clear: The bug does not happen to me in the Linux build of my program. I only see it with the Windows version.)

I honestly doubt it’s a bug within SDL. It probably works when you comment SDL_DestroyTexture and SDL_FreeSurface because you are basically destroying it before the renderer copies it into the render target. It is likely that the batching algorithm is kicking it and defers the copy later on when the flushing is required.

In order to confirm whether my assumption is correct just add SDL_RenderFlush(renderer) after SDL_RenderCopy within DrawText, but before SDL_DestroyTexture.

Normally I would never jump to that conclusion, except for Sylvain’s comment that this was “already fixed in SDL2”.

Since posting, I have (finally) managed to cross-build SDL2 for Windows from source, and I can verify that the bug no longer occurs in the latest mercurial snapshot (2.0.11-13399). So I will probably hack around the bug until 2.0.12 is released.

Sadly, this does not fix the bug. Which is too bad; it seemed like a reasonable explanation.

I’m also surprised to learn that there’s a function called SDL_RenderFlush(), since I literally spent half an hour looking for exactly such a function while I was trying to understand this issue. I guess that’s what I get for actually reading the documentation, instead of the include files like a chump! However, having read it now, I would have been very surprised if it had fixed the bug, since none of the listed prerequisites for its use apply.

1 Like

I do apologize then. I didn’t read his response correctly. Apparently it was a bug after all (?).

This is indeed the first thing I did assume. I had some time to work on a game with SDL Renderer, but apparently I did incorrectly assume that was the case in your issue. My bad.

Listed prerequisites are unlikely to cover this case though. It is very uncommon and bad practice to call malloc/free on textures while still being in a frame before flushing everything, yet alone do that each frame just to render some text. This is why I did give up on SDL2 TTF and just used FreeeType2 directly as SDL2 TTF seems to look like a perfect performance killer due to created surfaces and textures which need to be released later on. Right now I just render all glyphs into a texture when font is loaded and assemble text out of them later on. It is quite fast with SDL2 nowadays because of the batching algorithm.

I don’t blame you for the sarcasm. I think SDL_RenderFlush() has been available in a ‘stable’ release since 2.0.10 (so about six months) but if one searches for it in the official SDL2 documentation it says ‘Your search query “SDL_RenderFlush” didn’t return any results’. I have complained about this state of affairs before but it falls on deaf ears.