Skip to content

Commit

Permalink
Issue #7: fix performance issue with control event dispatch on iOS (p…
Browse files Browse the repository at this point in the history
…artial fix)
  • Loading branch information
starbugs committed Sep 16, 2012
1 parent aaabb9d commit 09ccded
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 61 deletions.
Binary file not shown.
6 changes: 6 additions & 0 deletions icedcoffee/ICHostViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@

icTime _deltaTime;
struct timeval _lastUpdate;
uint64_t _frameCount;

ICFrameUpdateMode _frameUpdateMode;
BOOL _needsDisplay;
Expand Down Expand Up @@ -202,6 +203,11 @@
*/
- (void)calculateDeltaTime;

/**
@brief The number of frames drawn by the receiver so far
*/
@property (nonatomic, readonly) uint64_t frameCount;

/**
@brief The frame update mode used to present the receiver's scene
Expand Down
2 changes: 2 additions & 0 deletions icedcoffee/ICHostViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ @implementation ICHostViewController
@synthesize scheduler = _scheduler;
@synthesize targetActionDispatcher = _targetActionDispatcher;
@synthesize frameUpdateMode = _frameUpdateMode;
@synthesize frameCount = _frameCount;
@synthesize didAlreadyCallViewDidLoad = _didAlreadyCallViewDidLoad;

+ (id)platformSpecificHostViewController
Expand Down Expand Up @@ -169,6 +170,7 @@ - (void)calculateDeltaTime
}

_lastUpdate = now;
_frameCount++;

#if IC_DEBUG_OUTPUT_FPS_ON_CONSOLE
// FIXME: this needs to be refactored so that it works generically and for multiple HVCs
Expand Down
1 change: 1 addition & 0 deletions icedcoffee/ICTouchEventDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
NSMutableDictionary *_dispatchTargetsForTouches;
NSMutableDictionary *_icTouchesForNativeTouches;
NSMutableDictionary *_draggingTouches;
uint64_t _currentControlDispatchFrame;
}

- (id)initWithHostViewController:(ICHostViewController *)hostViewController;
Expand Down
126 changes: 65 additions & 61 deletions icedcoffee/ICTouchEventDispatcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -185,69 +185,73 @@ - (void)dispatchControlEventsWithConvertedTouches:(NSDictionary *)convertedTouch
withTouchEvent:(ICTouchEvent *)touchEvent
selector:(SEL)selector
{
NSEnumerator *dispatchTargetEnumerator = [convertedTouches keyEnumerator];
ICNodeRef *dispatchTargetRef = nil;
while (dispatchTargetRef = [dispatchTargetEnumerator nextObject]) {
// Only dispatch control events if the given dispatch target is itself a control
// or a descendant of a control
ICControl *dispatchTarget = ICControlForNode([dispatchTargetRef node]);
if (dispatchTarget) {
// Iterate through all touches for the given control
NSDictionary *touchesDict = [convertedTouches objectForKey:dispatchTargetRef];
NSEnumerator *touchesEnumerator = [touchesDict objectEnumerator];
ICTouch *touch = nil;
while (touch = [touchesEnumerator nextObject]) {
// Find the current control the touch is over by performing another hit test.
// This is to compute correct control events for touches that moved or ended
// over another control than the dispatch target.
// FIXME: this causes bad performance for touchesMoved: events
ICNode *overNode = [self nodeForTouch:touch.nativeTouch];
ICControl *overControl = ICControlForNode(overNode);

// Compute the appropriate control event
ICControlEvents controlEvent = 0;
if (selector == SEL_TOUCHES_BEGAN) {
// Touch down control events
if (touch.tapCount > 1) {
controlEvent = ICControlEventTouchDownRepeat;
} else {
controlEvent = ICControlEventTouchDown;
}
} else if (selector == SEL_TOUCHES_MOVED) {
if (![self isDraggingTouch:touch]) {
// Start dragging
[self setDraggingTouch:touch];
// Immediately dispatch drag enter control event
[dispatchTarget sendActionsForControlEvent:ICControlEventTouchDragEnter
forEvent:touchEvent];
}
// Drag inside/outside
if (overControl == dispatchTarget) {
controlEvent = ICControlEventTouchDragInside;
} else {
controlEvent = ICControlEventTouchDragOutside;
}
} else if (selector == SEL_TOUCHES_ENDED) {
if ([self isDraggingTouch:touch]) {
// Stop dragging
[self removeDraggingTouch:touch];
// Immediately dispatch drag exit control event
[dispatchTarget sendActionsForControlEvent:ICControlEventTouchDragExit
forEvent:touchEvent];
}
// Touch up control events
if (overControl == dispatchTarget) {
controlEvent = ICControlEventTouchUpInside;
} else {
controlEvent = ICControlEventTouchUpOutside;
if (_hostViewController.frameCount != _currentControlDispatchFrame) {
// Issue #7: avoid processing multiple touchesMoved: events per frame
_currentControlDispatchFrame = _hostViewController.frameCount;

NSEnumerator *dispatchTargetEnumerator = [convertedTouches keyEnumerator];
ICNodeRef *dispatchTargetRef = nil;
while (dispatchTargetRef = [dispatchTargetEnumerator nextObject]) {
// Only dispatch control events if the given dispatch target is itself a control
// or a descendant of a control
ICControl *dispatchTarget = ICControlForNode([dispatchTargetRef node]);
if (dispatchTarget) {
// Iterate through all touches for the given control
NSDictionary *touchesDict = [convertedTouches objectForKey:dispatchTargetRef];
NSEnumerator *touchesEnumerator = [touchesDict objectEnumerator];
ICTouch *touch = nil;
while (touch = [touchesEnumerator nextObject]) {
// Find the current control the touch is over by performing another hit test.
// This is to compute correct control events for touches that moved or ended
// over another control than the dispatch target.
ICNode *overNode = [self nodeForTouch:touch.nativeTouch];
ICControl *overControl = ICControlForNode(overNode);

// Compute the appropriate control event
ICControlEvents controlEvent = 0;
if (selector == SEL_TOUCHES_BEGAN) {
// Touch down control events
if (touch.tapCount > 1) {
controlEvent = ICControlEventTouchDownRepeat;
} else {
controlEvent = ICControlEventTouchDown;
}
} else if (selector == SEL_TOUCHES_MOVED) {
if (![self isDraggingTouch:touch]) {
// Start dragging
[self setDraggingTouch:touch];
// Immediately dispatch drag enter control event
[dispatchTarget sendActionsForControlEvent:ICControlEventTouchDragEnter
forEvent:touchEvent];
}
// Drag inside/outside
if (overControl == dispatchTarget) {
controlEvent = ICControlEventTouchDragInside;
} else {
controlEvent = ICControlEventTouchDragOutside;
}
} else if (selector == SEL_TOUCHES_ENDED) {
if ([self isDraggingTouch:touch]) {
// Stop dragging
[self removeDraggingTouch:touch];
// Immediately dispatch drag exit control event
[dispatchTarget sendActionsForControlEvent:ICControlEventTouchDragExit
forEvent:touchEvent];
}
// Touch up control events
if (overControl == dispatchTarget) {
controlEvent = ICControlEventTouchUpInside;
} else {
controlEvent = ICControlEventTouchUpOutside;
}
} else if (selector == SEL_TOUCHES_CANCELLED) {
// Touch cancelled control event
controlEvent = ICControlEventTouchCancel;
}
} else if (selector == SEL_TOUCHES_CANCELLED) {
// Touch cancelled control event
controlEvent = ICControlEventTouchCancel;
// Dispatch control event
[dispatchTarget sendActionsForControlEvent:controlEvent forEvent:touchEvent];
}

// Dispatch control event
[dispatchTarget sendActionsForControlEvent:controlEvent forEvent:touchEvent];
}
}
}
Expand Down

0 comments on commit 09ccded

Please sign in to comment.