12-17-2014, 01:53 AM
(This post was last modified: 12-17-2014, 02:10 AM by belmont1990.)
As I said - it has nothing to do with insufficent CPU/GPU power while vsync is turned off, this stutter is due to some problem with aero/vsync and double buffering, nothing besides turning on vsync via d3doverrider or in pcsx2 seems to solve it, BUT turning vsync on really drops my performance and thats major problem.
I have adaptive v sync option in nvidia control panel but it doesn't affect pcsx2 at all.
EDIT: Just read this post taken from similiar thread from pcsx2 forum, regarding stuttering in win7 aero and gsdx.
Ver Greeneyes Wrotekay, well what happens is actually pretty simple, but I'll give it some context.
During each screen refresh (VDraw), a monitor draws the data that's stored in a buffer. If this buffer is updated mid-VDraw, you can get tearing if the new data is significantly different because a part of the screen was refreshed using the old data and another part gets the new data. To avoid this, the buffer should only be updated when the monitor isn't drawing, i.e. in VBlank (during this time, old CRT monitors were moving the electron gun back up to the top, but LCDs maintain the same behavior).
But how do you detect a VBlank? Well, monitors send a VBlank interrupt when they stop drawing, but unfortunately no operating system I know of allows this to trickle down to user mode (where programs run) code - so instead of having it trigger your presenting code at precisely the right time, you have to poll for it. You can either do this in a tight loop, which the OS won't like because it has other stuff to do, or poll it every millisecond or so and hope for the best (VBlank only lasts 0.5ms) - or come up with some elaborate hybrid. Even Direct3D, as far as I know, internally does the latter, and that can make it miss VBlanks and Present slightly late. Maybe OpenGl, being tied into your display driver, can actually do a better job and use the interrupt instead (at least internally). But this has lead to a situation where many people don't trust Direct3D to catch VBlanks for them, and use an elaborate polling system instead.
Enter the compositor. The compositor sits on top of all these interfaces, has access to the VBlank interrupts and so can take all the Present requests of the various programs running on the system and send them at that right time, that is, during VBlank - and thus avoid the tearing. This works great, but it doesn't play too well with code that tries to detect VBlank on its own, for one simple reason: by the time this code detects a VBlank has started, the compositor may have already rounded up all the Present requests and done its thing because it has access to the interrupt.
And this is where the stuttering happens: the program tries to display a frame roughly every VBlank, and without a compositor this works fine. Maybe it skips a frame every now and then, or maybe it drops one, but this will happen infrequently if the frame rate is close to the refresh rate. But now you've got the compositor taking care of VSync, and every now and then you detect the VBlank too late (even with your tight polling, if the OS interrupts your thread) and you miss the composition event, so the screen doesn't get updated. Then the next frame, you already have a frame queued up for presenting and you add another one, so that the previous frame gets skipped altogether. Now instead of presenting a single frame 99% of the time, maybe you only present a frame 67% of the time, based on how well your polling does (the more inconsistent your polling, the more likely you are to miss composition - in the worst case, you'll only present half your frames!).
This is the stutter you see, because the difference between 60fps and 30fps is pretty obvious when they randomly alternate. The solution is to let the compositor handle presenting, and wait for it to return - in the case of Windows' DWM, this means calling FlushDWM() which blocks until composition has happened. The difference in your code is actually pretty small: instead of polling for VBlank and presenting when it happens, you Present right away and then call FlushDWM(), letting the compositor take care of it. Note that Direct3D may be internally tied into the compositor in Windows and can probably do a better job when the compositor is enabled than when it isn't - but the aforementioned solution works just as well.
TL;DR: there's a race condition between the polling code and composition, so some frames end up missing the composition band wagon and getting skipped, causing other frames to be displayed for twice as long.
Anyway, I hope that helped you to understand the problem.
I have adaptive v sync option in nvidia control panel but it doesn't affect pcsx2 at all.
EDIT: Just read this post taken from similiar thread from pcsx2 forum, regarding stuttering in win7 aero and gsdx.
Ver Greeneyes Wrotekay, well what happens is actually pretty simple, but I'll give it some context.
During each screen refresh (VDraw), a monitor draws the data that's stored in a buffer. If this buffer is updated mid-VDraw, you can get tearing if the new data is significantly different because a part of the screen was refreshed using the old data and another part gets the new data. To avoid this, the buffer should only be updated when the monitor isn't drawing, i.e. in VBlank (during this time, old CRT monitors were moving the electron gun back up to the top, but LCDs maintain the same behavior).
But how do you detect a VBlank? Well, monitors send a VBlank interrupt when they stop drawing, but unfortunately no operating system I know of allows this to trickle down to user mode (where programs run) code - so instead of having it trigger your presenting code at precisely the right time, you have to poll for it. You can either do this in a tight loop, which the OS won't like because it has other stuff to do, or poll it every millisecond or so and hope for the best (VBlank only lasts 0.5ms) - or come up with some elaborate hybrid. Even Direct3D, as far as I know, internally does the latter, and that can make it miss VBlanks and Present slightly late. Maybe OpenGl, being tied into your display driver, can actually do a better job and use the interrupt instead (at least internally). But this has lead to a situation where many people don't trust Direct3D to catch VBlanks for them, and use an elaborate polling system instead.
Enter the compositor. The compositor sits on top of all these interfaces, has access to the VBlank interrupts and so can take all the Present requests of the various programs running on the system and send them at that right time, that is, during VBlank - and thus avoid the tearing. This works great, but it doesn't play too well with code that tries to detect VBlank on its own, for one simple reason: by the time this code detects a VBlank has started, the compositor may have already rounded up all the Present requests and done its thing because it has access to the interrupt.
And this is where the stuttering happens: the program tries to display a frame roughly every VBlank, and without a compositor this works fine. Maybe it skips a frame every now and then, or maybe it drops one, but this will happen infrequently if the frame rate is close to the refresh rate. But now you've got the compositor taking care of VSync, and every now and then you detect the VBlank too late (even with your tight polling, if the OS interrupts your thread) and you miss the composition event, so the screen doesn't get updated. Then the next frame, you already have a frame queued up for presenting and you add another one, so that the previous frame gets skipped altogether. Now instead of presenting a single frame 99% of the time, maybe you only present a frame 67% of the time, based on how well your polling does (the more inconsistent your polling, the more likely you are to miss composition - in the worst case, you'll only present half your frames!).
This is the stutter you see, because the difference between 60fps and 30fps is pretty obvious when they randomly alternate. The solution is to let the compositor handle presenting, and wait for it to return - in the case of Windows' DWM, this means calling FlushDWM() which blocks until composition has happened. The difference in your code is actually pretty small: instead of polling for VBlank and presenting when it happens, you Present right away and then call FlushDWM(), letting the compositor take care of it. Note that Direct3D may be internally tied into the compositor in Windows and can probably do a better job when the compositor is enabled than when it isn't - but the aforementioned solution works just as well.
TL;DR: there's a race condition between the polling code and composition, so some frames end up missing the composition band wagon and getting skipped, causing other frames to be displayed for twice as long.
Anyway, I hope that helped you to understand the problem.