1

In the event handling loop of SDL2, calling the method SDL_GetMouseState(&x,&y); or using event.motion.x and event.motion.y for the relative mouse coordinates makes SDL2 responsiveness VERY SLUGGISH. Whats weird is SDL_GetMouseState()is alot faster than event.motion.x and y, however they are both unbearably bad. Is there any other way of getting the mouse pos? You can even try this. I setup a simple text program in SDL2 to test something responsive such as scrolling, where you offset the y values. Try with and without vsync and with and without getting the mouse pos this way. I am currently using linux mint.

Code: (You will need arial.ttf in your folder where the project is if using codeblocks like i am)


#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h>
#include <string>
using std::string;
using std::to_string;





int main(int argc, char* argv[])
{


    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();

    SDL_Window *window = SDL_CreateWindow("Test Program", 0, 30, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_SHOWN);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );


    SDL_Event event;

    SDL_Point mousePos = {0,0};



    ///Fps vars
    int fpsCounter, fpsStart, fpsEnd;
    fpsStart = SDL_GetTicks();
    fpsEnd = SDL_GetTicks();
    fpsCounter = 0;
    TTF_Font *fpsFont = TTF_OpenFont("arial.ttf", 30);
    SDL_Surface *fpsSurface = TTF_RenderText_Blended(fpsFont, "FPS:  ", {0,0,0});
    SDL_Texture *fpsTexture = SDL_CreateTextureFromSurface(renderer, fpsSurface);
    SDL_FreeSurface(fpsSurface);
    int textW, textH, yVal;
    yVal = 50;
    SDL_QueryTexture(fpsTexture, NULL, NULL, &textW, &textH);
    SDL_Rect fpsRect = {1000, yVal, textW, textH};



    bool running = true;
    while (running)
    {




        while ( SDL_PollEvent(&event) )
        {
            if (event.type == SDL_QUIT)
            {
                running = false;
                break;
            }


            else if (event.type == SDL_MOUSEMOTION){

                int x,y;
                SDL_GetMouseState(&x,&y);
                mousePos = {x,y};
                break;
            }


            else if (event.type == SDL_MOUSEWHEEL){

                if (event.wheel.y > 0){  ///Scrolling up here
                    yVal -= 50;
                    fpsRect.y = yVal;
                    break;
                }
                if (event.wheel.y < 0){  ///Scrolling down here
                    yVal += 50;
                    fpsRect.y = yVal;
                    break;
                }
            }

        }


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



        //Update every 0.5s (500ms)
        fpsEnd = SDL_GetTicks();
        fpsCounter += 2;
        if ( (fpsEnd-fpsStart) > 500 ){
            fpsStart = SDL_GetTicks();

            SDL_DestroyTexture(fpsTexture);

            ///Change text
            string newText = ("FPS:  " + to_string(fpsCounter));
            fpsSurface = TTF_RenderText_Blended(fpsFont, newText.c_str(), {0,0,0});
            fpsTexture = SDL_CreateTextureFromSurface(renderer, fpsSurface);
            SDL_FreeSurface(fpsSurface);
            SDL_QueryTexture(fpsTexture, NULL, NULL, &textW, &textH);
            fpsRect = {1000, yVal, textW, textH};

            fpsCounter = 0;
        }


        SDL_RenderCopy(renderer, fpsTexture, NULL, &fpsRect);



        SDL_RenderPresent(renderer);


    }


    SDL_DestroyTexture(fpsTexture);
    TTF_CloseFont(fpsFont);


    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    TTF_Quit();
    SDL_Quit();



    return 0;

}


I don't agree that turning off VSYNC is a solution. It shouldn't be like this with VSYNC on regardless. It isn't like this in windows for some reason, it works fine there. Capping the FPS with SDL_Delay() to the refresh rate of the display also gives me the same problem.

  • 1
    Is there a good reason you respond to every SDL_MOUSEMOTION event by fetching the mouse state? Why not set a flag and fetch the mouse state once afterwards? – Botje Oct 06 '20 at 22:13
  • Yes, because if there is a mouse event, ie, clicking, I need to check if the mousePos WHEN CLICKED is on a box or something of the sort. – peter wilson Oct 06 '20 at 22:15
  • 2
    Also, try removing the `break` from the non-SDL_QUIT branches. I read [here](https://gamedev.stackexchange.com/questions/166194/sdl2-mouse-motion-event-keeps-occuring) that you can cause a buildup of events otherwise. Consider the case where 10 SDL_MOUSEMOTION events are on the queue: you will handle one, then render a frame, wait 16 ms, handle another one, etc. Taking 160 ms to process 10 mouse motion events instead of a single frame. – Botje Oct 06 '20 at 22:16
  • But `SDL_GetMouseState` will fetch the most recent mouse state, not the one at the point of the click. – Botje Oct 06 '20 at 22:19
  • 3
    Never `break` from the event look, unless you want to close the app. Don't use `SDL_GetMouseState` in the event loop, read the mouse position from the event you get. – HolyBlackCat Oct 06 '20 at 22:21
  • Ah, brilliant. Yes that works @ Botje n @ HolyBlackCat. Thanks! – peter wilson Oct 06 '20 at 22:23
  • Just to confirm, you mean to use ```event.motion.x ``` and ```event.motion.y``` @HolyBlackCat ? – peter wilson Oct 06 '20 at 22:23
  • Any relation to [the other Peter Wilson](https://stackoverflow.com/questions/64217083/sdl2-runs-extremely-poorly-with-relatively-low-fps-on-linux-mint)? – genpfault Oct 06 '20 at 23:49
  • 1
    @peterwilson Yep. *"I ran out of posts so I couldn't post the new example"* You can always edit the existing post. You don't have to make a new one. – HolyBlackCat Oct 07 '20 at 06:09

1 Answers1

1

The problem is that you "break" every time you get an event. So, your event queue is full all the time as you only process one event per draw.

Replace "break" with "continue" and process all events.

Milan Babuškov
  • 59,775
  • 49
  • 126
  • 179