SDL_WarpMouse() = really slow?

Started by
11 comments, last by choffstein 18 years, 6 months ago
I'm using SDL_WarpMouse() to reset my mouse for my rotateByMouse() function in my 3d camera class. It works right, it is just extremly laggy. Has anyone else used this function for a 3d camera? Does it work for you? Any input? BTW I'm on Linux Thanks
Advertisement
I looked around and didn't see any negative notes on it. Are you sure that calling it is causing the bottleneck? How often are you calling it? Does it lag only when the mouse is warped, or the whole time?

One thing to note is that warping the mouse will generate a mouse motion event, which can lead to some weird things if you warp the mouse if you're checking for the mouse position after a mouse move. Wow, that sentence was dizzy. Think circular calls. move -> warp -> move -> warp -> move -> pie.
There is no framerate drop, the framerate is extremly high. It is just that the movement of the mouse is laggy.

What you said makes sense.

I call SD_WarpMouse() every frame, and I also check for mouse events every frame. But I check for events first. Here is a simplified version of my code:

// Device.cpp //bool Device::run() {	SDL_Event event;	 	while(SDL_PollEvent(&event)) {		switch(event.type) {			case SDL_MOUSEMOTION:	           	m_vMousePos.x = event.motion.x;				m_vMousePos.y = event.motion.y;				break;			default:				break;		}	}				return active;}// Camera.pp //void Camera::setViewByMouse(dimension2d<unsigned short> screenSize, vector2di vMousePos) {		int middleX = screenSize.width  >> 1;				int middleY = screenSize.height >> 1;					float angleY = 0.0f;								float angleZ = 0.0f;								static float currentRotX = 0.0f;			if((vMousePos.x == middleX) && (vMousePos.y == middleY)) 		return;									angleY = (float)((middleX - vMousePos.x))/1000.0f;			angleZ = (float)((middleY - vMousePos.y))/1000.0f;			currentRotX -= angleZ;  	if(currentRotX > 1.45f) {		currentRotX = 1.45f;	}	else if(currentRotX < -1.45f) {		currentRotX = -1.45f;	}	else {		vector3df vAxis = (m_vTarget - m_vPos).crossProduct(m_vUp);		vAxis.normalize();		rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);		rotateView(angleY, 0, 1, 0);	}		SDL_WarpMouse(middleX, middleY);}// Main.cpp //// MAIN LOOP //while(device->run()) {		camera->setViewByMouse(renderer->getScreenSize(), device->getMousePos());				renderer->beginScene();		camera->render(renderer);		((OpenGLRenderer*)renderer)->renderTestCube(test.id);		renderer->endScene();	}


It might be hard to understand what is going on with just that small snippet.. But you will see that Device.run() runs every frame, and so does setViewByMouse().

Any ideas on how to make this faster?
Well, the mouse shouldn't be moving at all, jumping is how I would describe what I would expect the output to be. Is it the mouse cursor which is laggy or the motion of the camera itself?

If its just the cursor, I remember reading about a SDL function to make the cursor invisible (which may or may not be a viable solution).

If the camera is being laggy/jumping, I'd leap to some kind of rounding error (I can't seem to find any in your code, so I'm doubting that that would be the actual cause :/)

To toggle the visibility of the cursor, you can pass SDL_ENABLE/SDL_DISABLE to SDL_ShowCursor(int);
Since the mouse movement on most systems is velocity based, I would assume thats whats causing your lag if you move the mouse really slowly, it should appear smooth, but if you move it quickly then it will move further away from the point you warp it to, then when you warp it back it will appear to jump to the new position, this will give it an appearance of lag.
This line:

camera->setViewByMouse(renderer->getScreenSize(), device->getMousePos());

should really go in the SDL_MOUSEMOTION event handler, as it's being called when it doesn't need to be.

The situation is how Mushu described, with the self-perpetuating event cycle of doom. You could fix this by scrapping the event loop altogether, and use this method:

1. Use SDL_GetRelativeMouseState(int* x,int* y) to retrieve your x and y mouse cursor deltas each frame.
2. Call SDL_WarpMouse when the x and y deltas != 0. Then straight after call SDL_GetRelativeMouseState(...) to cancel out any affect WarpMouse might have on the relative mouse positions(I'm not sure if it does or not, you could experiment or just call GRMS just to be on the safe side).

This will stop the huge amount of unnecessary event processing, and hopefully fix your problem :)
Zenthos:

I changed some stuff...

Everything is in the one function. And I completely removed the mouse event in Device::run()

void Camera::setViewByMouse(dimension2d<unsigned short> screenSize) {					int middleX = screenSize.width  >> 1;				int middleY = screenSize.height >> 1;					float angleY = 0.0f;								float angleZ = 0.0f;								static float currentRotX = 0.0f;	int x, y;		SDL_GetRelativeMouseState(&x, &y);			if((x == middleX) && (y == middleY)) 		return;									angleY = (float)((middleX - x))/1000.0f;			angleZ = (float)((middleY - y))/1000.0f;			currentRotX -= angleZ;  	if(currentRotX > 1.45f) {		currentRotX = 1.45f;	}	else if(currentRotX < -1.45f) {		currentRotX = -1.45f;	}	else {		vector3df vAxis = (m_vTarget - m_vPos).crossProduct(m_vUp);		vAxis.normalize();		rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);		rotateView(angleY, 0, 1, 0);	}		SDL_WarpMouse(middleX, middleY);}


But now it doesn't work at all. The mouse returns at 0,0 on "SDL_GetRelativeMouseState(&x, &y);"

...
That code looks very familiar to me [wink] Common camera code I mean. Anyways, the problem I think is that when you use WarpMouse, it generates those mouse motion events, which end up countering your movements and cause lots of side effects, on of which is lag.

I found a way a while back that should fix that, so here's the revelant code segment. If you want to see the entire input library, here it is.

        // Warp the mouse	SDL_WarpMouse( X, Y );	// Pump all events	SDL_PumpEvents();	// Temporary event variable	SDL_Event msg;	// We want to preserve the events	std::vector<SDL_Event> eventList;	// Eat away the mouse motions	while( SDL_PollEvent( &msg ) )	{		// If it's not a mouse motion, we want it!		if( msg.type != SDL_MOUSEMOTION )		{			// Save it 			eventList.push_back( msg );		}	}	// Now go back and restore the event queue	for( int x = 0; x < eventList.size(); x++ )	{		SDL_PushEvent( &eventList.at(x) );	}


So simply add that stuff after you replace that SDL_WarpMouse and see if that does anything for the problem. Oh and if you need to see the function in the camera code that uses it, I can post that as well, just gotta find it first.
@Drew_Benton

there is a function

void SDL_SetEventFilter(SDL_EventFilter filter);

that takes a pointer to a "int" function that takes
an SDL_Event*

if you make your function return 1 said event will be added
otherwise it will be dropped

you could use that to drop all mouse motion events...

While that solution could probabally work rip-off, it would involve doing a lot more things rather than the simple thing I have done. When testing, the maximum number of events I could generate between that block of code was 1 event. So in essence, I was only pushing one event. I have it setup to handle multiple evemts of it happens, but as for my testing went, its a quick easy solution. Thanks though for the suggeston.

In reality, that code was added to ensure that not a single event would be discared. You could easily just have a while( SDL_PollEvent( &msg ) ); and not have anything major to worry about in simple cases, ones that do not use threads.

This topic is closed to new replies.

Advertisement