Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve compatability with Steam overlay #11

Open
magicmyth opened this issue Sep 27, 2017 · 12 comments
Open

Improve compatability with Steam overlay #11

magicmyth opened this issue Sep 27, 2017 · 12 comments

Comments

@magicmyth
Copy link
Contributor

This SDL2 port has greatly improved the stability of dosbox wrapped games for me with Linux in general and when running a game in Steam and using the Steam Controller there. However its not perfect as the Steam overlay can be very hit and miss and stall at times with dosbox. This is a known issue with dosbox as the optimisations of the old apps and dosbox itself means that the full frame updates are often very low and Steams overlay system requires frequent frame updates to work reliably. On Windows people have worked around the issue by using a DX pixel shader containing the statement bool forceupdate : FORCEUPDATE = true;. So I was wondering if it would be possible to do similar with a OpenGL shader and if so wondered if it would be a good idea to build such a feature directly into dosbox that could be enabled with a config option?

Thanks for doing this fork. Its really improved several old games for me on modern Linux distros.

@duganchen
Copy link
Owner

duganchen commented Sep 27, 2017

I'd like to mention the following immediately:

  1. I have indeed tested this (with the OpenGL 3 renderer) with the Steam overlay.

  2. This fork already disables one of the optimizations that reduced the frequency of full-frame updates in the original DosBox code. The nature of this optimization is described here:

gulikoza's comment

Without this optimization, I would think that this fork should be doing a full-frame update every frame.

As the workaround you posted is specific not only to the Direct3D renderer, but to Daum's fork's implementation of the Direct3D renderer, I'd actually like confirmation that this is actually an issue with the OpenGL 3 renderer.

@magicmyth
Copy link
Contributor Author

Testing with X-Wing and going by Steams FPS overlay and GALLIUM_HUD this does not seem to be the case. For example if you bring up one of the menus the FPS counter will drop to "1". If you activate the Steam overlay there it will tend to get stuck. Generally pressing Shift-tab then alt-tabing a few times will get it off again but not always. There are plenty of other areas in the game that show similar behaviour like various courtyards where the FPS seems to sit at about 8fps and rises only a few frames more when the cursor is being moved. In the actual game (fly in space) its outputs 70fps and I never have issue there with the overlay.

The touch menu huds of the controller don't work either but then I've found that unreliable in general with games.

BTW thanks for the link. I always like learning a little about why things are done the way they are even if I don't know much about graphic APIs.

@magicmyth
Copy link
Contributor Author

Confusing myself now as I'm writing two bug reports at the same time and thought I had mentioned that on this post :D

I'm on KDE Neon 5.10 (Ubuntu 16.04 base). I built your fork using the SDL and fluidsynth dev packages in the default Ubuntu 16.04. Ran ./autogen.sh && ./configure && make -j4.

Let me know if you need any more info.

@duganchen
Copy link
Owner

Yes, you did. I noticed that and deleted the question ("are you on Windows?)". Thanks for answering though.

@magicmyth
Copy link
Contributor Author

Just learnt something about Githubs issue page. It auto updates with new posts but does not remove deleted ones till you manually refresh the page. Today's lesson! :)

@duganchen
Copy link
Owner

I can't promise you I'll be able to make progress on this soon, but I did add Daum's fork as a branch named "daum". That should at least make it easier to start looking into how to port that part of Daum's Direct3D renderer to my OpenGL 3 renderer.

@magicmyth
Copy link
Contributor Author

No problem. I was not expecting anything immediate from anyone. Just wanted to get the issue out there so hopefully someone more knowledgeable than me on the subject can take a look.

When I get the time this seems like a good excuse to look at learning OpenGL again. Thanks for adding that branch. I can at least get some idea of the difference.

@magicmyth
Copy link
Contributor Author

I've done a little playing around. Now I know next to nothing about SDL and OpenGL a certainly not dosbox so all this is probably daft in the eyes of someone more experienced.

Anyway. Probing through the source I discovered an interesting bit in src/gui/render.cpp:RENDER_EndUpdate():

 // Force output to update the screen even if nothing changed...
 // works only with custom GLSL shaders (GFX_StartUpdate() was probably not even called)
if (render.forceUpdate) GFX_EndUpdate( 0 );

I have no idea where forceUpdate can be set or how it is relating to the GLSL shaders but thought it was good to note this part.

Anyway I've done a horrible hack as a proof of concept that forcing a minimal rate of frame updates allows Steam overlay to work reliably.

diff --git a/src/gui/render.cpp b/src/gui/render.cpp
index 224aad0..e72cf24 100644
--- a/src/gui/render.cpp
+++ b/src/gui/render.cpp
@@ -229,7 +229,8 @@ void RENDER_EndUpdate( bool abort ) {
 #endif
 		// Force output to update the screen even if nothing changed...
 		// works only with custom GLSL shaders (GFX_StartUpdate() was probably not even called)
-		if (render.forceUpdate) GFX_EndUpdate( 0 );
+		//if (render.forceUpdate) GFX_EndUpdate( 0 );
+		GFX_EndUpdate( 0 );
 	}
 	render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
 	render.updating=false;
diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp
index b31c7fc..7d667ce 100755
--- a/src/gui/sdlmain.cpp
+++ b/src/gui/sdlmain.cpp
@@ -1167,11 +1167,17 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
 
 
 void GFX_EndUpdate( const Bit16u *changedLines ) {
+	static Uint32 last_frame_update = GetTicks();
+
+	// Track how long since the last frame draw.
+	Uint32 time_since_update = GetTicks() - last_frame_update;
+
 	if (!sdl.update_display_contents)
 		return;
-	if (!sdl.updating)
+	if (!sdl.updating && (time_since_update < 100) )
 		return;
 	sdl.updating=false;
+	last_frame_update = GetTicks();
 	switch (sdl.desktop.type) {
 	case SCREEN_SURFACE:
 		if (changedLines) {
@@ -1217,10 +1223,14 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
 				}
 				index++;
 			}
-			glClear(GL_COLOR_BUFFER_BIT);
-			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-			SDL_GL_SwapWindow(sdl.window);
 		}
+		// Even if the lines did not change we show a frame. In combination
+		// with checking time_since_update this ensures a minimal amount
+		// of draws per-second.
+		glClear(GL_COLOR_BUFFER_BIT);
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		SDL_GL_SwapWindow(sdl.window);
+
 		break;
 #endif
 	default:

With that if the last draw time was more than a 10th of a second ago it forces a draw. Thus there is a minimal 10fps rendered. I've confirmed this works with Mesa's GALLIUM_HUD and Steam's overlay works perfectly now. Strangely this also seems to have fixed the Touch/Radial menu of the controller not displaying. I'll have to double check but I thought I had tried the radial menu in high FPS scenes and it was not working anywhere in X-Wing until this hack.

Just to be clear I'm not recommending this patch as I have no clue about the life time of any of these objects and a static variable within a function to track the last update time is not the right place to do this IMHO. It just a demonstration of where the issue with Steam's overlay (at least on Linux) lies.

@duganchen
Copy link
Owner

Very nice! If you put those changes in a pull request, I'll accept it (it sounds like you tested them).

@magicmyth
Copy link
Contributor Author

Thanks!

I'll hold of on making a pull request for a while till I have had time to study what is going on in more depth. I need to brush up on my C++ as well as I'm not sure the way I'm storing the last update time is thread safe. I don't know if tracking of updates should happen directly within GFX_EndUpdate() or whether it should be available elsewhere? Does GFX_EndUpdate() ever get called in different threads? There are a lot of checks to prevent the function doing anything if other bits are doing updates (sdl.updating) which my patch jumps past. Is that potentially going to cause a problem?

It seems render.cpp:RENDER_SetForceUpdate() is not used anywhere. I think we should hook this up to a config value so this behaviour can be toggled on/off and allow the user to override the default update cycle. That way at least we can avoid breaking existing behaviour.

As that function seems to come from NY00123's GLSL patch you based this on do you know how he intended it to be used? The code comments mention "works only with custom GLSL shaders" but what I have done does not care if custom shaders are in use (I think?).

I've only done testing with a couple of hours on X-Wing at the moment so I would like to test more games first. I might put a build up on the GOG forums to see how others get on with it first. If all goes well I'll make a pull request. I don't like to be one who breaks master so I'm cautious 😅

@magicmyth
Copy link
Contributor Author

I've made a fork with a polished up version on my force-frame-updates. I'll make a pull request soon, I just want to get a bit more testing done.

@duganchen
Copy link
Owner

I did get a pull request (from @timofonic) to address this:

#15

It wasn't building on Linux, so I ended up not being able to keep it.

The implementation is very likely worth studying and/or reworking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants