Mouse handling SDL2 very slow and sluggish in linux when VSYNC is turned ON

1.3k Views Asked by At

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

There are 1 best solutions below

0
On

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.