C# fonts corrupting

I’m using this C# wrapper to try to make a game with SDL flibitijibibo SDL2-CS.
My problem is, that after a while of displaying text, the font struct just doesn’t work anymore, even though I’ve used it for a couple of thousand frames and it used to be fine. TTF_RenderText_Solid returns null, and I get varying error messages using TTF_GetError . Here are some error messages:

  • “Text has zero width”
  • “Couldn’t find glyph”

When I reload the font, it works again for a couple of seconds.
I don’t think I have a memory leak, as the ram usage isn’t above 100mb

I’m using Windows 11 on my main Pc, but it also corrupted on my Windows 10 laptop. I don’t have any ram problems on either, and suspect the GC to be at fault due to the randomly occurring faults.
I’ve also tried to use glyphs, but I ran into the same problem.

Here’s some code I used (I’m using a more complex framework, that makes SDL more C#-Like (object oriented which is why I can’t share all the code):

  • The font loading code:
unsafe
{
    fixed (byte* pTtfBytes = ttfBytes)
    {
        rw = SDL.SDL_RWFromMem((nint)pTtfBytes, ttfBytes.Length);
        if (rw == nint.Zero)
            throw new Exception("Unable to convert ttfBytes into SDL_RWops");
        Font = SDL_ttf.TTF_OpenFontRW(rw, -1, pointSize);
        
        if (Font == nint.Zero)
        {
            throw new Exception("Unable to open font");
        }
    }
}
  • The code that creates a text surface
//.Font refers to the IntPtr returned by TTF_OpenFontRW
PSurface = SDL_ttf.TTF_RenderText_Solid(fontAsset.Font, text, color);
string error = SDL_ttf.TTF_GetError();
Debug.Assert(PSurface != 0); //<--- It breaks here
  • The code that creates a texture from the surface
        public ManagedTexture(Canvas canvas, ISurface surface, bool disposeSurface)
        {
            Texture = SDL.SDL_CreateTextureFromSurface(canvas.renderer, surface.PSurface);
            Debug.Assert(Texture != IntPtr.Zero);
            Canvas = canvas;
            if (disposeSurface)
                surface.Dispose();

        }
  • The code that calls these functions
            FontAsset fontAsset = new(store.GetRecourse("Fonts.Quicksand.Quicksand-Bold.ttf"), 100);
            //Infinite loop
                using ManagedTexture texture = new(canvas, fontAsset.WriteText($"Current fps: {fps}", new SDL2.SDL.SDL_Color() { r = 255, g = 255, b = 255 }), true);
               //[...] Rendering

I’m quite new to SDL programming and haven’t dealt much with manual memory management yet, so please forgive mistakes ^-^

Thank you

I’ve managed to pinpoint and resolve the issue! The problem arose when I was loading the SDL_RWops for TTF_OpenFontRW using SDL_RWFromMem. In this process, I passed in a byte array from managed memory and initially fixed it using the fixed statement:

fixed (byte* pTtfBytes = ttfBytes)
{
    rw = SDL.SDL_RWFromMem((nint)pTtfBytes, ttfBytes.Length);
    //[...]
}

However, the challenge was that after creating the SDL_RWops (which merely holds a reference to my byte array), the byte array was no longer fixed and could potentially be disposed of by the garbage collector.

In essence, if you’re loading a byte array from managed memory to an SDL_RWops, it’s crucial to ensure that the byte array used to create that object remains fixed. Here’s how you can achieve this:

GCHandle fixedByteArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pByteArray = fixedByteArray.AddrOfPinnedObject();
IntPtr rWops = SDL.SDL_RWFromMem(pByteArray, byteArray.Length);

I hope this helps anyone else encountering a similar issue! :blush:

1 Like