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

VideoCommon: New FrameTime/VBlank Analyzer + Graph #11326

Merged
merged 2 commits into from Dec 24, 2022

Conversation

Sam-Belliveau
Copy link
Contributor

@Sam-Belliveau Sam-Belliveau commented Dec 5, 2022

By moving some functions around, I was able to count the FPS / VPS in a much more consistent way that fixed the issue where ImmediateXFB would report an incorrect speed. I decided to detach the Speed counter from the VPS counter as the Audio Stretcher relies on the speed values that the speed counter reports.

I also added a "Time Counter" along with a Standard Deviation meant to better help developers determine if the frame pacing is consistent or not. This is useful because the FPS is not the only measure of smoothness, but so is the consistency of the frames being presented.

Here is what the UI looks like.

Frame.Time.Graph.mp4

image

image

image

image

image

image


Because audio stretching now uses this new performance tracker, it is able to more smoothly transition in and out of different game speeds, further reducing the stutters that occur during gameplay.


This new frametime system can reveal interesting behavior, such as how Super Mario Sunshine runs at unlimited speed:

image

Those shapes are caused by the VPS having a "fast cycle" than a "slow cycle." This type of analysis is impossible with something like MangoHud because that is unable to record Frames vs VBlanks.


It can show frame consistency with VSync on/off. [this data is specific to macOS, but should also apply elsewhere]

VSync On (fullscreen): [notice 60fps 😳]
image

VSync Off (fullscreen):
image


It can scale to make sure that everything fits on screen.
image

@MayImilae
Copy link
Contributor

MayImilae commented Dec 5, 2022

An audio stretching change in a videocommon PR is very peculiar. Why is that here and not in a different PR?

@Sam-Belliveau
Copy link
Contributor Author

An audio stretching change in a videocommon PR is very peculiar. Why is that here and not in a different PR?

Because of the way that gamespeed calculations are integral to the audiostretching, and the fact that the gamespeed is now calculated in a new way, the audio stretching is affected.

@mbc07
Copy link
Contributor

mbc07 commented Dec 6, 2022

I'm unsure about the "FTimes" and "VTimes" terms and can't even think how to translate that when accounting for localization. I was going to suggest changing "Show FTimes" to "Show Frame Times" but then there's the VTimes setting which is also related to the frame times (AFAICT). Any suggestion for distinguishing them?

@MayImilae
Copy link
Contributor

MayImilae commented Dec 6, 2022

The graphs need measures to be useful. Here's Digital Foundy's small frametime graph as a good example.

Screen Shot 2022-12-06 at 02 53 31

Though I'd recommend placing the measures on the inside of the box or something for aesthetic reasons. Also you don't need to invert it (0 at the top) the way they do if you don't want to, I'm just showing it as a good reference for a small graph like this.

Also I concur that FTimes and Vtimes is silly. You have plenty of space so you should just say Frame Times and V-blank Times.

I was going to suggest changing "Show FTimes" to "Show Frame Times" but then there's the VTimes setting which is also related to the frame times (AFAICT). Any suggestion for distinguishing them?

The exact same thing can be said about showing V-Blanks Per Second and Frames Per Second. They are very closely related so there's going to be a lot of overlap. Especially in a 50 or 60fps titles where they are -exactly the same-. I don't think there is really anything that can be done about that in this PR without challenging the paradigm, and I don't think this PR is the place to do that. One day a dedicated PR will challenge it and that is it certainly going to be a big discussion.

The only solution I can recommend for this is to move to one big graph. So have the three options along the top horizontally, and then one big graph below them that's just frametimes.

If you want more graphs, you could add a second graph below that that is based on the speed%. While the frametimes graph would be the most important for catching stuttering, the speed graph would act as a trendline for those battling to get to fullspeed. (not that a lot of people are doing that in Dolphin these days but you know) Especially if the speed graph has a longer sample window than the frametime graph (the size of the graphs would be the same, just, you know, more data in the same space to benefit their uses).

@mbc07
Copy link
Contributor

mbc07 commented Dec 6, 2022

Also I concur that FTimes and Vtimes is silly. You have plenty of space so you should just say Frame Times and V-blank Times.

This is enough to solve my concerns with the translation/localization. "Show Frame Times" and "Show V-Blank Times" are 100% more workable than just "Show FTimes" and "Show VTimes"...

@Sam-Belliveau
Copy link
Contributor Author

These all sound like good ideas, I'll probably be switching over to ImPlot to make these graphs and I'll add a single big graph underneath the FPS and VPS counters. I'll keep the standard deviation in the fps box, but the graph can be separate.

@Sam-Belliveau Sam-Belliveau changed the title VideoCommon: Add Frame Time Analyzer, Fix VPS Counting with ImmediateXFB, Improve Audio Stretching VideoCommon: New FrameTime/VBlank Analyzer + Graph Dec 9, 2022
@t895
Copy link
Contributor

t895 commented Dec 10, 2022

Is it possible to add a way to change the size of the graph? On small displays, the graph takes up a lot of space.
Screenshot_20221210-131355.png

@Sam-Belliveau
Copy link
Contributor Author

Sam-Belliveau commented Dec 10, 2022

I think it might be a good start to add some transparency to make it easier to see through, however I'll be sure to think about how we could resize things.

1X - Native:
image

2X - 720p:
image

3X - 1080p:
image

This depends on the UI scale of your device, so it wont look like this for everyone.

@MayImilae
Copy link
Contributor

I'm concerned about that scaling you set up and how it will work on the extremely high resolutions that I use for screenshots and such. I'll give it a test after you rebase the PR.

@Sam-Belliveau
Copy link
Contributor Author

I'm concerned about that scaling you set up and how it will work on the extremely high resolutions that I use for screenshots and such. I'll give it a test after you rebase the PR.

Ok I would like to clarify that the size of the FPS counter does not have anything to do with internal resolution. It depends on too things, the size of your window and the scaling of your desktop environment.

I used "automatically fit windows to resolution" to get a few standard resolutions to test it, but if your window remains the same size, the graph will not change.

@Sam-Belliveau
Copy link
Contributor Author

This refactor allows the frame time graph to have relatively messy code, but have that messy code be isolated from the rest of the code base.

I think that this PR is finally good for review.

@MayImilae
Copy link
Contributor

MayImilae commented Dec 14, 2022

@Sam-Belliveau I need to get in touch with you, please contact me via IRC or MayImilae#2884 on Dolphin's unofficial discord.

@dvessel
Copy link
Contributor

dvessel commented Dec 15, 2022

The performance graph looks really useful. It’s a nice addition. I have a question though.

I’m running Ventura and I can get the frame pacing locked in through a fixed refresh rate. It’s plainly visible if the pacing is off through the 240 test suite drop shadow test. If it doubles up frames, there’s a visible discontinuity. No games flickers frames like this but it’s only to show how well paced it is.

In the following video, Metal performance hud is enabled to show that I have my refresh rate set to 59.94Hz with good pacing. My question is about the numbers reported. It would make sense for the V-Blank numbers to match the display refresh rate since I can visually confirm that the pacing is perfect.

pacing.mov

Perfect pacing to will also depend on your video viewer of course. You can confirm the video is valid by stepping through each frame.

Is the mismatch due to some weirdness within Dolphin or the sampling code for getting the numbers? It doesn’t seem accurate.

@Sam-Belliveau
Copy link
Contributor Author

@dvessel

Maybe the point at which g_perf_metrics.CountVBlank() and g_perf_metrics.CountFrame() are being called is inconsistent? It has been hard to find where to record it, but I bet it's currently in the wrong spot.

@dvessel
Copy link
Contributor

dvessel commented Dec 15, 2022

Need to ask someone who is a lot more familiar with the graphics system. It looks like v-blanks are consistently syncing up with the refresh rate but the performance graph/numbers says otherwise.

PerformanceMetrics(PerformanceMetrics&&) = delete;
PerformanceMetrics& operator=(PerformanceMetrics&&) = delete;

public: // Count Functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have public 4 times, just have it once


void ImPlotPlotLines(const char* label) const;

private: // Functions for managing dt queue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here with the private/public. Also it's helpful if you group the functions by access type (where possible).

@iwubcode
Copy link
Contributor

implot is its own release separate from imgui. Therefore, it should be a submodule and not in with the imgui code (needs to be its own external). Could also make it a separate PR to make it a little easier to review.

@Rumi-Larry
Copy link

I would suggest to first make a pr to implement the fix relevant to ImmediateXFB , then add the implot submodule with the graph additions. A third pr could be the one aboit std:chrono.

@Sam-Belliveau Sam-Belliveau force-pushed the video-common-frame-pacing branch 2 times, most recently from a938cee to 0859b27 Compare December 23, 2022 04:22
@delroth
Copy link
Member

delroth commented Dec 24, 2022

@Sam-Belliveau when you have a chance, could you address the review comments from @iwubcode so we can move forward with this PR? Thanks!

@Sam-Belliveau
Copy link
Contributor Author

@Sam-Belliveau when you have a chance, could you address the review comments from @iwubcode so we can move forward with this PR? Thanks!

I addressed the one where he said i should remove the GetAverageFrameTimeMS(), but the public / private, i just like to split up my classes between methods and types, I'm not too sure about that one.

@delroth
Copy link
Member

delroth commented Dec 24, 2022

I addressed the one where he said i should remove the GetAverageFrameTimeMS(), but the public / private, i just like to split up my classes between methods and types, I'm not too sure about that one.

FWIW I also think the redundant "public"/"private" specifiers are unusual and don't fit the project's normal style. I think keeping the // comments you already have to logically distinguish the groups of methods is a good idea though. Any strong objection?

(In general if you disagree with a code review comment - which is fine, many things in code are subjective preferences - please reply to it still so we know it was looked at and not just ignored.)

@Sam-Belliveau
Copy link
Contributor Author

Yeah sorry about that, I'll remove the redundant specifiers so we can get to merging.

@Sam-Belliveau
Copy link
Contributor Author

The performance graph looks really useful. It’s a nice addition. I have a question though.

I’m running Ventura and I can get the frame pacing locked in through a fixed refresh rate. It’s plainly visible if the pacing is off through the 240 test suite drop shadow test. If it doubles up frames, there’s a visible discontinuity. No games flickers frames like this but it’s only to show how well paced it is.

In the following video, Metal performance hud is enabled to show that I have my refresh rate set to 59.94Hz with good pacing. My question is about the numbers reported. It would make sense for the V-Blank numbers to match the display refresh rate since I can visually confirm that the pacing is perfect.

pacing.mov
Perfect pacing to will also depend on your video viewer of course. You can confirm the video is valid by stepping through each frame.

Is the mismatch due to some weirdness within Dolphin or the sampling code for getting the numbers? It doesn’t seem accurate.

also to clarify, the reason the two seem so mismatched is because they have vsync on, and the timings get thrown out of wack with VSync, but thats an issue for the next PR.

Copy link
Member

@delroth delroth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a round of reviews myself, overall this change looks fine to me. I have a bunch of optional comments for you to look at and maybe fix in a future PR, I don't want to block this from being merged now (@JMC47 really wants it in before christmas :P). Many of these comments are very general and might apply in future code you write for the project, please try to incorporate this feedback into future PRs you contribute.

Thank you!

PerformanceTracker m_speed_counter{nullptr, 6000000};
};

extern PerformanceMetrics g_perf_metrics;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a huge fan of adding more global state, in the future please attempt to avoid it as much as possible (by e.g. moving it to be a member of some other object that uses it).


double PerformanceTracker::GetHzAvg() const
{
std::lock_guard lock{m_mutex};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of these could be reader locks (std::shared_lock) to save a bit on contention. In practice it's unlikely to make a difference here, this seems like it's mostly single reader / single writer in the current workload. But using reader locks doesn't make anything more complicated, so in general I prefer doing it regardless.

std::shared_mutex is also marginally better in general for various historical reasons: https://stackoverflow.com/questions/69990339/why-is-stdmutex-so-much-worse-than-stdshared-mutex-in-visual-c

int m_on_state_changed_handle;

// Name of log file and file stream
const char* m_log_name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO having this be std::string (and thus having ownership of the string data) would be better, vs. the user of this object having to maintain the filename alive until this object is deleted. Right now it doesn't make a huge difference because (I think) this is only ever being used with constant strings, but in the future it could lead to confusion.

@delroth delroth merged commit ea19909 into dolphin-emu:master Dec 24, 2022
10 of 11 checks passed
@Pokechu22
Copy link
Contributor

This seems to have caused the % speed indicator to change too slowly. Both FPS and VPS update about at the rate they should, but % speed takes a lot longer to change. This is easiest seen on the homebrew channel or the safety screen on the Wii Menu, where you can hold TAB to fast-forward to ~500 FPS. If you hold it for a few seconds and then release, the FPS and VPS values will quickly update to match, but the % speed will slowly increase even after you release and then will start to drop down afterwards. I suspect this also causes bad results with audio stretching, but I haven't tested extensively.

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