mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +00:00
Back to asynchronous updates and drawing, to try to improve guarantees on audio latency; experimenting with whether other parts of the approach are fundamentally flawed; added a broad-phase for scheduled updates on the 2600.
This commit is contained in:
parent
11073daee1
commit
e3b95b8d2b
@ -283,57 +283,63 @@ void Machine::output_pixels(unsigned int count)
|
||||
{
|
||||
while(count--)
|
||||
{
|
||||
// apply any queued changes and flush the record
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveSetup)
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates)
|
||||
{
|
||||
_stateByTime = _stateByExtendTime[1];
|
||||
|
||||
// clear any ongoing moves
|
||||
if(_hMoveFlags)
|
||||
// apply any queued changes and flush the record
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveSetup)
|
||||
{
|
||||
for(int c = 0; c < number_of_upcoming_events; c++)
|
||||
// schedule an extended left border
|
||||
_stateByTime = _stateByExtendTime[1];
|
||||
|
||||
// clear any ongoing moves
|
||||
if(_hMoveFlags)
|
||||
{
|
||||
_upcomingEvents[c].updates &= ~(Event::Action::HMoveCompare | Event::Action::HMoveDecrement);
|
||||
for(int c = 0; c < number_of_upcoming_events; c++)
|
||||
{
|
||||
_upcomingEvents[c].updates &= ~(Event::Action::HMoveCompare | Event::Action::HMoveDecrement);
|
||||
}
|
||||
}
|
||||
|
||||
// schedule new moves
|
||||
_hMoveFlags = 0x1f;
|
||||
_hMoveCounter = 15;
|
||||
|
||||
// follow-through into a compare immediately
|
||||
_upcomingEvents[_upcomingEventsPointer].updates |= Event::Action::HMoveCompare;
|
||||
}
|
||||
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveCompare)
|
||||
{
|
||||
for(int c = 0; c < 5; c++)
|
||||
{
|
||||
if(((_objectMotion[c] >> 4)^_hMoveCounter) == 7)
|
||||
{
|
||||
_hMoveFlags &= ~(1 << c);
|
||||
}
|
||||
}
|
||||
if(_hMoveFlags)
|
||||
{
|
||||
if(_hMoveCounter) _hMoveCounter--;
|
||||
_upcomingEvents[(_upcomingEventsPointer+4)%number_of_upcoming_events].updates |= Event::Action::HMoveCompare;
|
||||
_upcomingEvents[(_upcomingEventsPointer+2)%number_of_upcoming_events].updates |= Event::Action::HMoveDecrement;
|
||||
}
|
||||
}
|
||||
|
||||
// schedule new moves
|
||||
_hMoveFlags = 0x1f;
|
||||
_hMoveCounter = 15;
|
||||
|
||||
// follow-through into a compare immediately
|
||||
_upcomingEvents[_upcomingEventsPointer].updates |= Event::Action::HMoveCompare;
|
||||
}
|
||||
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveCompare)
|
||||
{
|
||||
for(int c = 0; c < 5; c++)
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveDecrement)
|
||||
{
|
||||
if(((_objectMotion[c] >> 4)^_hMoveCounter) == 7)
|
||||
{
|
||||
_hMoveFlags &= ~(1 << c);
|
||||
}
|
||||
update_timers(_hMoveFlags);
|
||||
}
|
||||
if(_hMoveFlags)
|
||||
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::ResetCounter)
|
||||
{
|
||||
if(_hMoveCounter) _hMoveCounter--;
|
||||
_upcomingEvents[(_upcomingEventsPointer+4)%number_of_upcoming_events].updates |= Event::Action::HMoveCompare;
|
||||
_upcomingEvents[(_upcomingEventsPointer+2)%number_of_upcoming_events].updates |= Event::Action::HMoveDecrement;
|
||||
_objectCounter[_objectCounterPointer][_upcomingEvents[_upcomingEventsPointer].counter].count = 0;
|
||||
}
|
||||
|
||||
// zero out current update event
|
||||
_upcomingEvents[_upcomingEventsPointer].updates = 0;
|
||||
}
|
||||
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveDecrement)
|
||||
{
|
||||
update_timers(_hMoveFlags);
|
||||
}
|
||||
|
||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::ResetCounter)
|
||||
{
|
||||
_objectCounter[_objectCounterPointer][_upcomingEvents[_upcomingEventsPointer].counter].count = 0;
|
||||
}
|
||||
|
||||
// zero out current update event, progress to next
|
||||
_upcomingEvents[_upcomingEventsPointer].updates = 0;
|
||||
// progress to next event
|
||||
_upcomingEventsPointer = (_upcomingEventsPointer + 1)%number_of_upcoming_events;
|
||||
|
||||
// determine which output state is currently active
|
||||
@ -392,6 +398,7 @@ void Machine::output_pixels(unsigned int count)
|
||||
_horizontalTimer = (_horizontalTimer + 1) % horizontalTimerPeriod;
|
||||
if(!_horizontalTimer)
|
||||
{
|
||||
// switch back to a normal length left border
|
||||
_stateByTime = _stateByExtendTime[0];
|
||||
set_ready_line(false);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
const unsigned int number_of_upcoming_events = 16;
|
||||
const unsigned int number_of_upcoming_events = 6;
|
||||
const unsigned int number_of_recorded_counters = 7;
|
||||
|
||||
class Speaker: public ::Outputs::Filter<Speaker> {
|
||||
|
@ -34,7 +34,9 @@
|
||||
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
|
||||
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
|
||||
|
||||
_serialDispatchQueue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
|
||||
// create a serial dispatch queue
|
||||
_serialDispatchQueue = dispatch_queue_create("OpenGLView", DISPATCH_QUEUE_SERIAL);
|
||||
// dispatch_set_target_queue(_serialDispatchQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
|
||||
// set the clear colour
|
||||
[self.openGLContext makeCurrentContext];
|
||||
@ -63,20 +65,21 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
||||
BOOL didSkip = _hasSkipped;
|
||||
dispatch_async(_serialDispatchQueue, ^{
|
||||
[self.delegate openGLView:self didUpdateToTime:time didSkipPreviousUpdate:didSkip frequency:frequency];
|
||||
[self drawViewOnlyIfDirty:YES];
|
||||
OSAtomicTestAndClear(processingMask, &_updateIsOngoing);
|
||||
});
|
||||
_hasSkipped = NO;
|
||||
NSLog(@"+");
|
||||
}
|
||||
else
|
||||
{
|
||||
_hasSkipped = YES;
|
||||
NSLog(@"-");
|
||||
}
|
||||
|
||||
// Draw the display only if a previous draw is not still ongoing. -drawViewOnlyIfDirty: is guaranteed
|
||||
// to be safe to call concurrently with -openGLView:updateToTime: so there's no need to worry about
|
||||
// the above interrupting the below or vice versa.
|
||||
if(_hasSkipped && !OSAtomicTestAndSet(drawingMask, &_updateIsOngoing))
|
||||
if(!OSAtomicTestAndSet(drawingMask, &_updateIsOngoing))
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
[self drawViewOnlyIfDirty:YES];
|
||||
|
Loading…
Reference in New Issue
Block a user