SDL2 memory usage doesn't fully decrease after freeing surfaces and destroying textures with TTF

370 views Asked by At

This has been happening since I have started using SDL_TTF, but I can't locate the reason for it. When I create a text object, the program sits at x amount of ram usage forever until I do something (nothing wrong there). When I then add text, the programs ram usage increases. Also nothing wrong there. But when I decide to remove text, at first, the programs ram usage INCREASES from where its at for some reason, and then decreases as it should, however it never EVER decreases to how it was exactly before with the same text. If I keep repeating adding and subtracting text, the memory just keeps slowly going up.

Here is what I mean:

BEFORE enter image description here

AFTER TEXT IS ADDED

enter image description here

AFTER TEXT IS REMOVED

enter image description here

If it isn't clear in the photos, the program begins at 102.8mb ram usage. When text is added it jumps to 104mb and then after the text is removed, the program goes back to 103.6mb usage. What on earth is using the extra megabyte of ram???

Here is my code for Text objects, and where it is called in a function.

text.h


#ifndef TEXT_H
#define TEXT_H

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

#include "events.h"


#include <iostream>
#include <string>
#include <vector>
using std::vector;
using std::string;
using std::cout;
using std::endl;
using std::exception;



class Text
{
    public:
        Events EVENTS;
        Text(void);


        ///Public variables
        static vector <TTF_Font*> fonts;
        const int lowestFontSize = 1;
        const int highestFontSize = 100;
        int fontIndex;

        int textSize;
        SDL_Rect textRect;
        int x;
        int y;
        int initialX, initialY;
        bool setup;

        static int numOfInstances;



        ///Functions
        void Setup(SDL_Renderer *renderer, string txt, int x, int y, int txtSize, SDL_Color Colour = {0,0,0}, bool isBold = false, string fontType = "arial.ttf", bool isWrapped=false, int theWrapWidth=0);

        string Get_Text();
        void Change_Text(SDL_Renderer *renderer, string newText);
        void Draw_Text(SDL_Renderer *renderer);
        void Change_Position(SDL_Renderer *renderer, int xPos, int yPos);
        void Change_Position_And_Text(SDL_Renderer *renderer, int xPos, int yPos, string newText);

        int Text_Width(int FirstCharIndex, int numOfCharsPastFirstIndex);
        int Text_Height(int FirstCharIndex, int numOfCharsPastFirstIndex);


        void Free_All();


    private:

        ///SDL stuff
        SDL_Texture *textTexture;
        SDL_Surface *textSurface;



        SDL_Color colour;
        SDL_Point point;

        ///text varibales
        string text;
        int textW;
        int textH;
        bool bold;
        bool wrapped;
        int wrappedWidth;




};


#endif

text.cpp

#include "text.h"


int Text::numOfInstances = 0;

vector <TTF_Font*> Text::fonts;


Text::Text()
{
    setup = false;


    textTexture = NULL;
    textSurface = NULL;


}


void Text::Setup(SDL_Renderer *renderer, string txt, int xPos, int yPos, int txtSize, SDL_Color Colour, bool isBold, string fontType, bool isWrapped, int theWrapWidth )
{
    if (setup == false){


        numOfInstances += 1;


        wrapped = isWrapped;
        wrappedWidth = theWrapWidth;
        text = txt;
        textSize = txtSize;
        bold = isBold;
        colour = Colour;


        textW = 0;
        textH = 0;
        x = xPos;
        y = yPos;
        initialX = x;
        initialY = y;


        fontIndex = textSize-lowestFontSize -1;


        ///One time setups
        if (numOfInstances == 1){
            try{
                TTF_Init();
                //cout << "Initialised ttf" << endl;
            }
            catch (exception &err){
                cout << "Could not initialise ttf for text \"" << text << "\". Error from SDL is: " << TTF_GetError() << ". Error from C++ is: " << err.what() << endl;
            }

            for (int i=lowestFontSize; i <= highestFontSize; i++){
                TTF_Font *currentFont = TTF_OpenFont(fontType.c_str(), i);
                if (!currentFont){
                    cout << "Error with font in text \"" << txt << "\" Error is: " << SDL_GetError() << endl;
                }

                //TTF_SetFontKerning(currentFont, 0);


                fonts.push_back(currentFont);
            }

        }



        if (bold == true){
            TTF_SetFontStyle(fonts[fontIndex], TTF_STYLE_BOLD);
        }


        if (!SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" ) ){  ///2 is highest

            cout << "Text rendering quality not enabled " << text << endl;
        }

        if (text != ""){    ///Only create textures if there is text

            if (wrapped == true){
                textSurface = TTF_RenderText_Blended_Wrapped(fonts[fontIndex], text.c_str(), colour, wrappedWidth);     ///Recreate the textures/surfaces
            }
            else{
                textSurface = TTF_RenderText_Blended(fonts[fontIndex], text.c_str(), colour);     ///Recreate the textures/surfaces
            }
            if (!textSurface){
                cout << "Unable to create surface of text " << text << " error is: " << SDL_GetError() << endl;
            }
            textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
            if (!textTexture){
                cout << "Unable to create texture from surface of text " << text << " error is: " << SDL_GetError() << endl;
            }

            SDL_FreeSurface(textSurface);
            textSurface = NULL;

            SDL_QueryTexture(textTexture, NULL, NULL, &textW, &textH);
            textRect = {x, y, textW, textH};
        }






        point = {0, 0};

        setup = true;





    }



    else{
        //cout << "Trying to setup a text already setup! " << text << endl;
    }


}





void Text::Change_Position_And_Text(SDL_Renderer *renderer, int xPos, int yPos, string newText )
{
    if (setup == true){
        text = newText;
        x = xPos;
        y = yPos;
        textRect.x = x;
        textRect.y = y;



        if (textTexture != NULL){
            SDL_DestroyTexture(textTexture);    ///Free memory not going to be used again.
            textTexture = NULL;
        }

        if (wrapped == true){
             textSurface = TTF_RenderText_Blended_Wrapped(fonts[fontIndex], text.c_str(), colour, wrappedWidth);     ///Recreate the textures/surfaces
        }
        else{
            textSurface = TTF_RenderText_Blended(fonts[fontIndex], text.c_str(), colour);     ///Recreate the textures/surfaces
        }
        if (!textSurface){
            cout << "Unable to create surface of text " << text << " error is: " << SDL_GetError() << endl;
        }
        textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
        if (!textTexture){
            cout << "Unable to create texture from surface of text " << text << " error is: " << SDL_GetError() << endl;
        }

        SDL_FreeSurface(textSurface);
        textSurface = NULL;

        SDL_QueryTexture(textTexture, NULL, NULL, &textW, &textH);   ///neeed this
        textRect = {x, y, textW, textH};
    }
}



void Text::Change_Position(SDL_Renderer *renderer,  int xPos, int yPos)
{
    if (setup == true){
        x = xPos;
        y = yPos ;
        textRect.x = xPos;
        textRect.y = yPos;
    }
}





void Text::Change_Text(SDL_Renderer *renderer, string newText)
{
    if (setup == true){
        text = newText;

        if (textTexture != NULL){
            SDL_DestroyTexture(textTexture);    ///Free memory not going to be used again.
            textTexture = NULL;
        }


        if (text != ""){

            if (wrapped == true){
                textSurface = TTF_RenderText_Blended_Wrapped(fonts[fontIndex], text.c_str(), colour, wrappedWidth);     ///Recreate the textures/surfaces
            }
            else{
                textSurface = TTF_RenderText_Blended(fonts[fontIndex], text.c_str(), colour);     ///Recreate the textures/surfaces
            }
            if (!textSurface){
                cout << "Unable to create surface of text " << text << " error is: " << SDL_GetError() << endl;
            }
            textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
            if (!textTexture){
                cout << "Unable to create texture from surface of text " << text << " error is: " << SDL_GetError() << endl;
            }

            SDL_FreeSurface(textSurface);
            textSurface = NULL;

            SDL_QueryTexture(textTexture, NULL, NULL, &textW, &textH);      ///neeed this
            textRect = {x, y, textW, textH};

        }

    }


}



int Text::Text_Width(int FirstCharIndex, int numOfCharsPastFirstIndex)
{
    int w,h;

    string textSelection = text.substr(FirstCharIndex, numOfCharsPastFirstIndex);

    TTF_SizeText(fonts[fontIndex], textSelection.c_str(), &w, &h);

    return w;
}


int Text::Text_Height(int FirstCharIndex, int numOfCharsPastFirstIndex)
{
    int w,h;

    string textSelection = text.substr(FirstCharIndex, numOfCharsPastFirstIndex);

    TTF_SizeText(fonts[fontIndex], textSelection.c_str(), &w, &h);

    return h;
}



string Text::Get_Text()
{
    if (setup == true){
        return text;
    }
    else{
        return "";
        //cout << "Text not setup when trying to obtain text through Get_Text() function" << endl;
    }
}


void Text::Draw_Text(SDL_Renderer *renderer)
{
    if (setup == true){
        //cout << numOfInstances << endl;

        if (SDL_PointInRect(&EVENTS.mousePos, &textRect)   &&    EVENTS.currentCursor !=  SDL_SYSTEM_CURSOR_IBEAM){
            EVENTS.Change_Cursor(SDL_SYSTEM_CURSOR_IBEAM);
        }

        SDL_RenderCopy(renderer, textTexture, NULL, &textRect);
    }
    else{
        //cout << "Text not setup when trying to draw it in Draw_Text() function" << endl;
    }

}




void Text::Free_All()
{
    if (setup == true){


        if (textSurface == NULL){
            //cout << "Text surface already free'd" << endl;
        }
        else{
            SDL_FreeSurface(textSurface);
            textSurface = NULL;
            //cout << "Free'd surface \n";
        }

        if (textTexture == NULL){
            //cout << "Could not free memory for text \"" << text << "\". Error from SDL is: " << TTF_GetError() << endl;
        }
        else{
            SDL_DestroyTexture(textTexture);
            textTexture = NULL;
        }





        if (numOfInstances == 1){

            for (int i=0; i <= (highestFontSize-lowestFontSize); i++){
                TTF_CloseFont(fonts[i]);
                //cout << "Closed " << lowestFontSize+i << endl;
            }

            try{
                TTF_Quit();
                //cout << "Quit ttf" << endl;
            }
            catch (exception &err){
                cout << "Could not quit ttf for text \"" << text << "\". Error from SDL is: " << TTF_GetError() << ". Error from C++ is: " << err.what() << endl;
            }
        }


        ///For TTF_Init();
        numOfInstances -= 1;



        //cout << "Free'd " << text << endl;

    }




    else{
        //cout << "Text not setup yet when trying to free!" << endl;
    }



    setup = false;


}


And the function I use to display text:


void Test::Setup(SDL_Renderer *renderer)
{
    if (setup == false){
        setup = true;


        testText.Setup(renderer, "", 300, 200, 30);

    }

}



void Test::Tester(SDL_Renderer *renderer)
{

    Setup(renderer);



    if (EVENTS.currentKey != ""){
        testText.Change_Text(renderer, testText.Get_Text() + EVENTS.currentKey);
    }

    if (EVENTS.pasteText == true){
        testText.Change_Text(renderer, testText.Get_Text() + SDL_GetClipboardText());
    }

    if (EVENTS.backspacePressed == true){
        if (testText.Get_Text() != "") {
            string tempText = (testText.Get_Text());
            tempText.pop_back();
            testText.Change_Text(renderer, tempText);
        }
    }



    testText.Draw_Text(renderer);


}


0

There are 0 answers