-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
[Android] Support restore emulator state #6270
[Android] Support restore emulator state #6270
Conversation
To test the screen been killed case, go to developer options then check the option Don't keep activities Then start any game, press home, press recent apps and open Dolphin again |
Here are a few (untested) native methods you can use: master...JosJuice:restore-state-helpers
I suggest that you use A hack that hardcodes the duration 2 seconds isn't mergeable in my opinion. I can vaguely recall that someone started working on making the core be able to load a savestate on its own when booting... I don't remember the details about that (or even if it's true that someone started working on it), but we would need something like that. |
Huh, apparently the core already has a way to load savestates at boot ( |
@JosJuice I am a bit confused about this isRunning() method, will it return true after I stop the emulation? because otherwise it will not be helpful since I have to stop the emulation as soon as the screen is being killed for any reason, but I need to know if the native code still has the ability to resume emulation after the distraction of the screen, can that method help? |
If you call |
I don't see why we would have to stop emulation when the screen is killed. In master, it's possible to rotate the screen without stopping emulation. |
because of the other case, if the OS decided to kill the activity I will have to run the emulation form the start, but I managed to find a way to distinguish between those 2 cases at last :) for now I think I don't need IsRunning() btw thanks a lot for your quick help :) |
54ad664
to
7c0f560
Compare
Yes, you'll have to run the emulation from the start if the system kills the Dolphin process, but that doesn't mean that you have to stop emulation manually in advance. If the Dolphin process is killed, the emulation will automatically be in the "stopped" state the next time the process starts up, and Or do you mean that something goes wrong when the emulation was "automatically stopped" like that? |
I am afraid there is a situation where the screen is killed but the native code still there and actually has the content and can resume emulation, because I tried to start the emulation after screen being killed, it doesn't work unless I stop the emulation manually, can you explain why? |
I suppose that Android is killing the activity without killing the whole process. (Maybe that's how the "Don't keep activities" option works?) The native code isn't bound to any activity, so killing activities has no effect on it.
|
7c0f560
to
96afa52
Compare
@JosJuice I cherry-picked the helper methods commit from your repo and ended up in a mess here, I will fix that later |
Please don't store the savestate in the cache directory, otherwise it might get deleted automatically even though we haven't finished using it yet. The cache directory is intended for data that can be reobtained if needed. If you want Dolphin to use as little storage as possible, my suggestion is to make EDIT: No wait, |
96afa52
to
cbd469e
Compare
FYI, #6271 has now been merged :) |
I've pushed two new commits to the same branch as before. The first one adds the ability to load a savestate at boot, as made possible by PR #6271. The second one adds the ability to make Like before, this is untested. I've only confirmed that it compiles. |
cbd469e
to
f41c782
Compare
f41c782
to
bc7cbb0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This round of pointing out things to fix is probably the last round unless I've missed something :)
|
||
private String getTemporaryStateFilePath() | ||
{ | ||
return getContext().getCacheDir() + File.separator + "temp.sav"; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
} | ||
else | ||
{ | ||
loadPreviousTemporaryState = true; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
if (!isManualExit) | ||
{ | ||
mEmulationFragment.saveTemporaryState(); | ||
} |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Log.debug("[EmulationFragment] activity resumed or fresh start"); | ||
// activity resumed without being killed or this is the first run | ||
deleteFile(temporaryStatePath); | ||
} |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
…s killed 1) Most of the times the native heap is kept around even after the activity is killed, we can ask the native code if it is still running and resume the emulation if that is the case. 2) In case the native heap is freed and the emulation can't resume we used a temporary state to load on the game boot. I couldn't find a way to test this, if you want to test this schnario, add this block to EmulationFragment. public void onDestroy() { stopEmulation(); super.onDestroy(); } onDestroy is only called if the acivity killed by the OS and not be rotation change whihch in this case will make sure to kill the emulation and start again when the activiy is re-created.
bc7cbb0
to
136e835
Compare
@JosJuice ready for the final review and hopefully to be merged. Thanks a lot for your help! |
Do we need to pause/resume here at all? |
@degasus during the onPause I can't tell if this is orientation change or you are leaving the emulation to another app, not pausing means the emulation will keep running for the later case |
Can't you use |
I didn't know that method exist! theoretically I can do that but I have to hack again emulationState.run() to pick another flow if this is an orientation change, what is the benefit of not pausing the emulation? I am not sure if it worth all the checks/flag that need to be added to support this. |
I don't know how worth not pausing is, but it would be nice if we could skip creating a savestate if we know that the activity is just changing configuration. |
@JosJuice you are right, I will make this enhancement soon |
@JosJuice just checked the code again, we are creating the temporary saves state inside onSaveInstance which is not called when the configuration is changed, so nothing to improve here! |
Why wouldn't onSaveInstanceState be called when changing configuration? If it isn't called, I don't see how "regular" apps wouldn't lose data such as form contents when rotating the screen. I would've taken a look at this myself to verify what actually happens, but my only working Android device stopped working yesterday :( |
I don't know what I was thinking when I write that comment. I am glad you are following with me on the Android changes, otherwise it would be a mess! |
Support restore emulator state after emulation screen is killed
This is more tricky that what I expected and I need help from the emulator core devs. Really sorry for the huge text below, putting it here easier to go over all of these on the chat :)
Problem I am trying to solve
if you leave the app by opening another app or pressing the home button, the emulator screen might be killed and we need to restore the state if you come back to Dolphin again.
The proposed solution
While leaving the app we are going to save the state on special slot (8) for this situation then when you come back we will decide if we need to load the temporary state we saved or not.
Problems I need help with
1. in Android there is no way to tell if the screen got killed because you switched the approtation or because of memory limitation while your app in the background and this makes the situation harder because during rotation we can theoretically pause/resume the emulation but in the other case since the OS decided to kill the screen we might not have the emulation state to resume the emulation so we have to load the temporary saved sate.But, in order to do that I have to stop the emulation during onDestroy phase because running the emulation while previous emulation was not stopped caused an error "broken pipe". Stoping the emulation caused the pause/resume ability during rotation changed to stop working and now we are loading the temp saved state even in the case of rotating change.If the native library can inform the app that it still has the previous emulation state and can continue, the app will be able to distinguish between the two cases and use the saved state only when needed.Or
I wonder if the app rotation is important for Dolphin, can't we just look the emulation to landscape on mobile devices? I think PPSSPP is doing that.2. Loading the state should only happen after the game start running, there is no way the app can tell if the game start running, a hack is done inside surfaceChanged() that load the state after 2 seconds of running the game.3. Keeping those temporary states might not be a good thing to do, if we can have a way to delete states that would make it better.In this PR we have a working solution that can restart the state during screen rotation or after screen been killed. The downside is the during the rotation now you will loose the EFP copies since we are loading the state and it will stutter because of the 2 seconds delay hack.EDIT: All cases are testing and hopefully are working fine.
The final status for each case: