1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-28 07:29:45 +00:00

Moves drawing into the next timer tick after retrace if sync locked.

... which should mean it occurs within 1/600th of a second of announced retrace, which I assume always will be less than the retrace period. So: does the frame buffer update during retrace.

This should completely eliminate tearing for machines that can be synced to the native output rate.
This commit is contained in:
Thomas Harte 2020-02-08 18:07:13 -05:00
parent 7c0f3bb237
commit b76a5870b3
2 changed files with 20 additions and 12 deletions

View File

@ -67,7 +67,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableASanStackUseAfterReturn = "YES"

View File

@ -157,6 +157,7 @@ struct ActivityObserver: public Activity::Observer {
int64_t _syncTime;
int64_t _timeDiff;
double _refreshPeriod;
BOOL _isSyncLocking;
std::unique_ptr<Outputs::Display::OpenGL::ScanTarget> _scanTarget;
}
@ -712,6 +713,7 @@ struct ActivityObserver: public Activity::Observer {
const auto timeNow = std::chrono::high_resolution_clock::now().time_since_epoch().count();
CGSize pixelSize = view.backingSize;
BOOL isSyncLocking;
@synchronized(self) {
// Store a means to map from CVTimeStamp.hostTime to std::chrono::high_resolution_clock;
// there is an extremely dodgy assumption here that both are in the same units (and, below, that both as in ns).
@ -727,12 +729,17 @@ struct ActivityObserver: public Activity::Observer {
// Set the current refresh period.
_refreshPeriod = double(now->videoRefreshPeriod) / double(now->videoTimeScale);
// Determine where responsibility lies for drawing.
isSyncLocking = _isSyncLocking;
}
// Draw the current output. (TODO: do this within the timer if either raster racing or, at least, sync matching).
[self.view performWithGLContext:^{
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
} flushDrawable:YES];
if(!isSyncLocking) {
[self.view performWithGLContext:^{
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
} flushDrawable:YES];
}
}
#define TICKS 600
@ -766,6 +773,7 @@ struct ActivityObserver: public Activity::Observer {
splitAndSync = ratio <= maximumAdjustment && ratio >= 1 / maximumAdjustment;
}
}
self->_isSyncLocking = splitAndSync;
// If the time window is being split, run up to the split, then check out machine speed, possibly
// adjusting multiplier, then run after the split.
@ -804,19 +812,19 @@ struct ActivityObserver: public Activity::Observer {
// a concluding draw. Implicit assumption here: whatever is left to be done in the final window
// can be done within the retrace period.
auto wasUpdating = self->_isUpdating.test_and_set();
// if(wasUpdating && splitAndSync) {
// while(self->_isUpdating.test_and_set());
// wasUpdating = false;
// }
if(wasUpdating && splitAndSync) {
while(self->_isUpdating.test_and_set());
wasUpdating = false;
}
if(!wasUpdating) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
[self.view performWithGLContext:^{
self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
// if(splitAndSync) {
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
// }
} flushDrawable:NO];
if(splitAndSync) {
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
}
} flushDrawable:splitAndSync];
self->_isUpdating.clear();
});
}