mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-10 01:54:25 +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:
parent
7c0f3bb237
commit
b76a5870b3
@ -67,7 +67,7 @@
|
|||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Release"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
enableASanStackUseAfterReturn = "YES"
|
enableASanStackUseAfterReturn = "YES"
|
||||||
|
@ -157,6 +157,7 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
int64_t _syncTime;
|
int64_t _syncTime;
|
||||||
int64_t _timeDiff;
|
int64_t _timeDiff;
|
||||||
double _refreshPeriod;
|
double _refreshPeriod;
|
||||||
|
BOOL _isSyncLocking;
|
||||||
|
|
||||||
std::unique_ptr<Outputs::Display::OpenGL::ScanTarget> _scanTarget;
|
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();
|
const auto timeNow = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||||
|
|
||||||
CGSize pixelSize = view.backingSize;
|
CGSize pixelSize = view.backingSize;
|
||||||
|
BOOL isSyncLocking;
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
// Store a means to map from CVTimeStamp.hostTime to std::chrono::high_resolution_clock;
|
// 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).
|
// there is an extremely dodgy assumption here that both are in the same units (and, below, that both as in ns).
|
||||||
@ -727,13 +729,18 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
|
|
||||||
// Set the current refresh period.
|
// Set the current refresh period.
|
||||||
_refreshPeriod = double(now->videoRefreshPeriod) / double(now->videoTimeScale);
|
_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).
|
// Draw the current output. (TODO: do this within the timer if either raster racing or, at least, sync matching).
|
||||||
|
if(!isSyncLocking) {
|
||||||
[self.view performWithGLContext:^{
|
[self.view performWithGLContext:^{
|
||||||
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
||||||
} flushDrawable:YES];
|
} flushDrawable:YES];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define TICKS 600
|
#define TICKS 600
|
||||||
|
|
||||||
@ -766,6 +773,7 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
splitAndSync = ratio <= maximumAdjustment && ratio >= 1 / maximumAdjustment;
|
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
|
// 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.
|
// 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
|
// a concluding draw. Implicit assumption here: whatever is left to be done in the final window
|
||||||
// can be done within the retrace period.
|
// can be done within the retrace period.
|
||||||
auto wasUpdating = self->_isUpdating.test_and_set();
|
auto wasUpdating = self->_isUpdating.test_and_set();
|
||||||
// if(wasUpdating && splitAndSync) {
|
if(wasUpdating && splitAndSync) {
|
||||||
// while(self->_isUpdating.test_and_set());
|
while(self->_isUpdating.test_and_set());
|
||||||
// wasUpdating = false;
|
wasUpdating = false;
|
||||||
// }
|
}
|
||||||
if(!wasUpdating) {
|
if(!wasUpdating) {
|
||||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
[self.view performWithGLContext:^{
|
[self.view performWithGLContext:^{
|
||||||
self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
|
self->_scanTarget->update((int)pixelSize.width, (int)pixelSize.height);
|
||||||
|
|
||||||
// if(splitAndSync) {
|
if(splitAndSync) {
|
||||||
// self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
self->_scanTarget->draw((int)pixelSize.width, (int)pixelSize.height);
|
||||||
// }
|
}
|
||||||
} flushDrawable:NO];
|
} flushDrawable:splitAndSync];
|
||||||
self->_isUpdating.clear();
|
self->_isUpdating.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user