mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Efficiency improvements to consolidate display events for the window-less preload range.
This commit is contained in:
parent
7f59beb195
commit
9669f147ba
@ -192,6 +192,29 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
return [_ASDisplayLayer class];
|
return [_ASDisplayLayer class];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)scheduleNodeForDisplay:(ASDisplayNode *)node
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
static NSMutableSet *nodesToDisplay = nil;
|
||||||
|
static BOOL displayScheduled = NO;
|
||||||
|
if (!nodesToDisplay) {
|
||||||
|
nodesToDisplay = [[NSMutableSet alloc] init];
|
||||||
|
}
|
||||||
|
[nodesToDisplay addObject:node];
|
||||||
|
if (!displayScheduled) {
|
||||||
|
displayScheduled = YES;
|
||||||
|
// It's essenital that any layout pass that is scheduled during the current
|
||||||
|
// runloop has a chance to be applied / scheduled, so always perform this after the current runloop.
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
displayScheduled = NO;
|
||||||
|
for (ASDisplayNode *node in nodesToDisplay) {
|
||||||
|
[node __recursivelyTriggerDisplayAndBlock:NO];
|
||||||
|
}
|
||||||
|
nodesToDisplay = nil;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Lifecycle
|
#pragma mark - Lifecycle
|
||||||
|
|
||||||
- (void)_staticInitialize
|
- (void)_staticInitialize
|
||||||
@ -705,6 +728,20 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
[self displayImmediately];
|
[self displayImmediately];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)__setNeedsDisplay
|
||||||
|
{
|
||||||
|
ASDisplayNode *rasterizedContainerNode = [self __rasterizedContainerNode];
|
||||||
|
if (rasterizedContainerNode) {
|
||||||
|
[rasterizedContainerNode setNeedsDisplay];
|
||||||
|
} else {
|
||||||
|
[_layer setNeedsDisplay];
|
||||||
|
|
||||||
|
if (_layer && !self.isSynchronous && self.displaysAsynchronously) {
|
||||||
|
[ASDisplayNode scheduleNodeForDisplay:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)__setNeedsLayout
|
- (void)__setNeedsLayout
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertThreadAffinity(self);
|
ASDisplayNodeAssertThreadAffinity(self);
|
||||||
@ -1417,7 +1454,7 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
[_placeholderLayer removeFromSuperlayer];
|
[_placeholderLayer removeFromSuperlayer];
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||||
{
|
{
|
||||||
// This recursion must handle layers in various states:
|
// This recursion must handle layers in various states:
|
||||||
// 1. Just added to hierarchy, CA hasn't yet called -display
|
// 1. Just added to hierarchy, CA hasn't yet called -display
|
||||||
@ -1436,9 +1473,10 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
|
|
||||||
// Kick off the recursion first, so that all necessary display calls are sent and the displayQueue is full of parallelizable work.
|
// Kick off the recursion first, so that all necessary display calls are sent and the displayQueue is full of parallelizable work.
|
||||||
for (CALayer *sublayer in layer.sublayers) {
|
for (CALayer *sublayer in layer.sublayers) {
|
||||||
recursivelyEnsureDisplayForLayer(sublayer);
|
recursivelyTriggerDisplayForLayer(sublayer, shouldBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldBlock) {
|
||||||
// As the recursion unwinds, verify each transaction is complete and block if it is not.
|
// As the recursion unwinds, verify each transaction is complete and block if it is not.
|
||||||
// While blocking on one transaction, others may be completing concurrently, so it doesn't matter which blocks first.
|
// While blocking on one transaction, others may be completing concurrently, so it doesn't matter which blocks first.
|
||||||
BOOL waitUntilComplete = (!node.shouldBypassEnsureDisplay);
|
BOOL waitUntilComplete = (!node.shouldBypassEnsureDisplay);
|
||||||
@ -1450,8 +1488,9 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)recursivelyEnsureDisplay
|
- (void)__recursivelyTriggerDisplayAndBlock:(BOOL)shouldBlock
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
// ASDisplayNodeAssert(self.isNodeLoaded, @"Node must have layer or view loaded to use -recursivelyEnsureDisplay");
|
// ASDisplayNodeAssert(self.isNodeLoaded, @"Node must have layer or view loaded to use -recursivelyEnsureDisplay");
|
||||||
@ -1464,7 +1503,12 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
if ([layer needsLayout]) {
|
if ([layer needsLayout]) {
|
||||||
[layer layoutIfNeeded];
|
[layer layoutIfNeeded];
|
||||||
}
|
}
|
||||||
recursivelyEnsureDisplayForLayer(layer);
|
recursivelyTriggerDisplayForLayer(layer, shouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)recursivelyEnsureDisplay
|
||||||
|
{
|
||||||
|
[self __recursivelyTriggerDisplayAndBlock:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setShouldBypassEnsureDisplay:(BOOL)shouldBypassEnsureDisplay
|
- (void)setShouldBypassEnsureDisplay:(BOOL)shouldBypassEnsureDisplay
|
||||||
@ -1997,6 +2041,7 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer,
|
|||||||
return _replaceAsyncSentinel != nil;
|
return _replaceAsyncSentinel != nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This method doesn't appear to be called, and should be removed.
|
||||||
- (ASSentinel *)_asyncReplaceSentinel
|
- (ASSentinel *)_asyncReplaceSentinel
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
|||||||
@ -303,10 +303,9 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
// for async display, capture the current displaySentinel value to bail early when the job is executed if another is
|
// for async display, capture the current displaySentinel value to bail early when the job is executed if another is
|
||||||
// enqueued
|
// enqueued
|
||||||
// for sync display, just use nil for the displaySentinel and go
|
// for sync display, just use nil for the displaySentinel and go
|
||||||
//
|
|
||||||
// REVIEW: what about the degenerate case where we are calling setNeedsDisplay faster than the jobs are dequeuing
|
// FIXME: what about the degenerate case where we are calling setNeedsDisplay faster than the jobs are dequeuing
|
||||||
// from the displayQueue? do we want to put in some kind of timer to not cancel early fails from displaySentinel
|
// from the displayQueue? Need to not cancel early fails from displaySentinel changes.
|
||||||
// changes?
|
|
||||||
ASSentinel *displaySentinel = (asynchronously ? _displaySentinel : nil);
|
ASSentinel *displaySentinel = (asynchronously ? _displaySentinel : nil);
|
||||||
int64_t displaySentinelValue = [displaySentinel increment];
|
int64_t displaySentinelValue = [displaySentinel increment];
|
||||||
|
|
||||||
|
|||||||
@ -218,20 +218,12 @@
|
|||||||
|
|
||||||
- (void)setNeedsDisplay
|
- (void)setNeedsDisplay
|
||||||
{
|
{
|
||||||
ASDisplayNode *rasterizedContainerNode = [self __rasterizedContainerNode];
|
_bridge_prologue;
|
||||||
if (rasterizedContainerNode) {
|
// Send the message to the layer first, as __setNeedsDisplay may call -displayIfNeeded.
|
||||||
[rasterizedContainerNode setNeedsDisplay];
|
// REVIEW: Audit if this is necessary or if it can be called after like __setNeedsLayout
|
||||||
} else {
|
// -> Likely possible because of the aggregation / trampoline to occur on a later runloop.
|
||||||
[_layer setNeedsDisplay];
|
_messageToLayer(setNeedsDisplay);
|
||||||
|
[self __setNeedsDisplay];
|
||||||
if (_layer && !self.isSynchronous && self.displaysAsynchronously) {
|
|
||||||
// It's essenital that any layout pass that is scheduled during the current
|
|
||||||
// runloop has a chance to be applied / scheduled.
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self recursivelyEnsureDisplay];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNeedsLayout
|
- (void)setNeedsLayout
|
||||||
|
|||||||
@ -149,6 +149,8 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
|||||||
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
||||||
- (void)displayImmediately;
|
- (void)displayImmediately;
|
||||||
|
|
||||||
|
- (void)__setNeedsDisplay;
|
||||||
|
|
||||||
// Returns the ancestor node that rasterizes descendants, or nil if none.
|
// Returns the ancestor node that rasterizes descendants, or nil if none.
|
||||||
- (ASDisplayNode *)__rasterizedContainerNode;
|
- (ASDisplayNode *)__rasterizedContainerNode;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user