Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an experimental "no-copy" renderer #741

Merged
merged 9 commits into from
Jan 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@
CCCCCCE41EC3EF060087FE10 /* NSParagraphStyle+ASText.m in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCD41EC3EF060087FE10 /* NSParagraphStyle+ASText.m */; };
CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */ = {isa = PBXBuildFile; fileRef = CCCCCCE51EC3F0FC0087FE10 /* NSAttributedString+ASText.h */; };
CCCCCCE81EC3F0FC0087FE10 /* NSAttributedString+ASText.m in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCE61EC3F0FC0087FE10 /* NSAttributedString+ASText.m */; };
CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.m in Sources */ = {isa = PBXBuildFile; fileRef = CCDC9B4C200991D10063C1F8 /* ASGraphicsContext.m */; };
CCDD148B1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCDD148A1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.m */; };
CCE4F9B31F0D60AC00062E4E /* ASIntegerMapTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCE4F9B21F0D60AC00062E4E /* ASIntegerMapTests.m */; };
CCE4F9B51F0DA4F300062E4E /* ASLayoutEngineTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCE4F9B41F0DA4F300062E4E /* ASLayoutEngineTests.mm */; };
Expand Down Expand Up @@ -895,6 +897,8 @@
CCCCCCD41EC3EF060087FE10 /* NSParagraphStyle+ASText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSParagraphStyle+ASText.m"; sourceTree = "<group>"; };
CCCCCCE51EC3F0FC0087FE10 /* NSAttributedString+ASText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+ASText.h"; sourceTree = "<group>"; };
CCCCCCE61EC3F0FC0087FE10 /* NSAttributedString+ASText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+ASText.m"; sourceTree = "<group>"; };
CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASGraphicsContext.h; sourceTree = "<group>"; };
CCDC9B4C200991D10063C1F8 /* ASGraphicsContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASGraphicsContext.m; sourceTree = "<group>"; };
CCDD148A1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionModernDataSourceTests.m; sourceTree = "<group>"; };
CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASSectionController.h; sourceTree = "<group>"; };
CCE04B201E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IGListAdapter+AsyncDisplayKit.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1270,6 +1274,8 @@
058D09E1195D050800B7D73C /* Details */ = {
isa = PBXGroup;
children = (
CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */,
CCDC9B4C200991D10063C1F8 /* ASGraphicsContext.m */,
CC5601391F06E9A700DC4FBE /* ASIntegerMap.h */,
CC56013A1F06E9A700DC4FBE /* ASIntegerMap.mm */,
CC0F885E1E4280B800576FED /* _ASCollectionViewCell.h */,
Expand Down Expand Up @@ -1836,6 +1842,7 @@
68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */,
CCCCCCE11EC3EF060087FE10 /* ASTextUtilities.h in Headers */,
B350624B1B010EFD0018CF92 /* _ASPendingState.h in Headers */,
CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */,
E5C347B11ECB3D9200EC4BE4 /* ASBatchFetchingDelegate.h in Headers */,
CC54A81C1D70079800296A24 /* ASDispatch.h in Headers */,
B350624D1B010EFD0018CF92 /* _ASScopeTimer.h in Headers */,
Expand Down Expand Up @@ -2268,6 +2275,7 @@
E5B078001E69F4EB00C24B5B /* ASElementMap.m in Sources */,
9C8898BC1C738BA800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */,
690ED59B1E36D118000627C0 /* ASImageNode+tvOS.m in Sources */,
CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.m in Sources */,
CCCCCCD81EC3EF060087FE10 /* ASTextInput.m in Sources */,
34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */,
DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Add new unit testing to the layout engine. [Adlai Holler](https://github.com/Adlai-Holler) [#424](https://github.com/TextureGroup/Texture/pull/424)
- [Automatic Subnode Management] Nodes with ASM enabled now insert/delete their subnodes as soon as they enter preload state, so the subnodes can preload too. [Huy Nguyen](https://github.com/nguyenhuy) [#706](https://github.com/TextureGroup/Texture/pull/706)
- [ASCollectionNode] Added support for interactive item movement. [Adlai Holler](https://github.com/Adlai-Holler)
- Added an experimental "no-copy" rendering API. See ASGraphicsContext.h for info. [Adlai Holler](https://github.com/Adlai-Holler)

## 2.6
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
Expand Down
2 changes: 1 addition & 1 deletion Dangerfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ end

# Ensure new files have proper header
new_source_license_header = <<-HEREDOC
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand Down
7 changes: 3 additions & 4 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#import <AsyncDisplayKit/ASDimension.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASEqualityHelpers.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>
#import <AsyncDisplayKit/ASInternalHelpers.h>
#import <AsyncDisplayKit/ASLayoutElementStylePrivate.h>
#import <AsyncDisplayKit/ASLayoutSpec.h>
Expand Down Expand Up @@ -1507,7 +1508,7 @@ - (void)_updateClipCornerLayerContentsWithRadius:(CGFloat)radius backgroundColor
BOOL isRight = (idx == 1 || idx == 2);

CGSize size = CGSizeMake(radius + 1, radius + 1);
UIGraphicsBeginImageContextWithOptions(size, NO, self.contentsScaleForDisplay);
ASGraphicsBeginImageContextWithOptions(size, NO, self.contentsScaleForDisplay);

CGContextRef ctx = UIGraphicsGetCurrentContext();
if (isRight == YES) {
Expand All @@ -1524,11 +1525,9 @@ - (void)_updateClipCornerLayerContentsWithRadius:(CGFloat)radius backgroundColor

// No lock needed, as _clipCornerLayers is only modified on the main thread.
CALayer *clipCornerLayer = _clipCornerLayers[idx];
clipCornerLayer.contents = (id)(UIGraphicsGetImageFromCurrentImageContext().CGImage);
clipCornerLayer.contents = (id)(ASGraphicsGetImageAndEndCurrentContext().CGImage);
clipCornerLayer.bounds = CGRectMake(0.0, 0.0, size.width, size.height);
clipCornerLayer.anchorPoint = CGPointMake(isRight ? 1.0 : 0.0, isTop ? 1.0 : 0.0);

UIGraphicsEndImageContext();
}
[self _layoutClipCornersIfNeeded];
});
Expand Down
25 changes: 10 additions & 15 deletions Source/ASImageNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#import <AsyncDisplayKit/ASDisplayNode+FrameworkSubclasses.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>
#import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASTextNode.h>
#import <AsyncDisplayKit/ASImageNode+AnimatedImagePrivate.h>
Expand Down Expand Up @@ -213,11 +214,10 @@ - (UIImage *)placeholderImage

ASDN::MutexLocker l(__instanceLock__);

UIGraphicsBeginImageContext(size);
ASGraphicsBeginImageContextWithOptions(size, NO, 1);
[self.placeholderColor setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *image = ASGraphicsGetImageAndEndCurrentContext();

return image;
}
Expand Down Expand Up @@ -472,7 +472,7 @@ + (ASWeakMapEntry *)contentsForkey:(ASImageNodeContentsKey *)key drawParameters:

+ (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)drawParameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
{
// The following `UIGraphicsBeginImageContextWithOptions` call will sometimes take take longer than 5ms on an
// The following `ASGraphicsBeginImageContextWithOptions` call will sometimes take take longer than 5ms on an
// A5 processor for a 400x800 backingSize.
// Check for cancellation before we call it.
if (isCancelled()) {
Expand All @@ -481,7 +481,7 @@ + (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(

// Use contentsScale of 1.0 and do the contentsScale handling in boundsSizeInPixels so ASCroppedImageBackingSizeAndDrawRectInBounds
// will do its rounding on pixel instead of point boundaries
UIGraphicsBeginImageContextWithOptions(key.backingSize, key.isOpaque, 1.0);
ASGraphicsBeginImageContextWithOptions(key.backingSize, key.isOpaque, 1.0);

BOOL contextIsClean = YES;

Expand Down Expand Up @@ -529,9 +529,7 @@ + (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(
return nil;
}

UIImage *result = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();
UIImage *result = ASGraphicsGetImageAndEndCurrentContext();

if (key.imageModificationBlock) {
result = key.imageModificationBlock(result);
Expand Down Expand Up @@ -742,7 +740,7 @@ - (NSDictionary *)debugLabelAttributes
extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor)
{
return ^(UIImage *originalImage) {
UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, originalImage.scale);
ASGraphicsBeginImageContextWithOptions(originalImage.size, NO, originalImage.scale);
UIBezierPath *roundOutline = [UIBezierPath bezierPathWithOvalInRect:(CGRect){CGPointZero, originalImage.size}];

// Make the image round
Expand All @@ -758,24 +756,21 @@ extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(
[roundOutline stroke];
}

UIImage *modifiedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return modifiedImage;
return ASGraphicsGetImageAndEndCurrentContext();
};
}

extern asimagenode_modification_block_t ASImageNodeTintColorModificationBlock(UIColor *color)
{
return ^(UIImage *originalImage) {
UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, originalImage.scale);
ASGraphicsBeginImageContextWithOptions(originalImage.size, NO, originalImage.scale);

// Set color and render template
[color setFill];
UIImage *templateImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[templateImage drawAtPoint:CGPointZero blendMode:kCGBlendModeCopy alpha:1];

UIImage *modifiedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *modifiedImage = ASGraphicsGetImageAndEndCurrentContext();

// if the original image was stretchy, keep it stretchy
if (!UIEdgeInsetsEqualToEdgeInsets(originalImage.capInsets, UIEdgeInsetsZero)) {
Expand Down
6 changes: 3 additions & 3 deletions Source/ASMapNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#import <AsyncDisplayKit/ASDisplayNode+FrameworkSubclasses.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>
#import <AsyncDisplayKit/ASInsetLayoutSpec.h>
#import <AsyncDisplayKit/ASInternalHelpers.h>
#import <AsyncDisplayKit/ASLayout.h>
Expand Down Expand Up @@ -222,7 +223,7 @@ - (void)takeSnapshot

CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);

UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
ASGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
[image drawAtPoint:CGPointZero];

UIImage *pinImage;
Expand Down Expand Up @@ -254,8 +255,7 @@ - (void)takeSnapshot
}
}

image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
image = ASGraphicsGetImageAndEndCurrentContext();
}

strongSelf.image = image;
Expand Down
6 changes: 3 additions & 3 deletions Source/ASTextNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#import <AsyncDisplayKit/ASDisplayNode+FrameworkSubclasses.h>
#import <AsyncDisplayKit/ASHighlightOverlayLayer.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>

#import <AsyncDisplayKit/ASTextKitCoreTextAdditions.h>
#import <AsyncDisplayKit/ASTextKitRenderer+Positioning.h>
Expand Down Expand Up @@ -907,7 +908,7 @@ - (UIImage *)placeholderImage

ASDN::MutexLocker l(__instanceLock__);

UIGraphicsBeginImageContext(size);
ASGraphicsBeginImageContextWithOptions(size, NO, 1.0);
[self.placeholderColor setFill];

ASTextKitRenderer *renderer = [self _locked_renderer];
Expand All @@ -926,8 +927,7 @@ - (UIImage *)placeholderImage
}
}

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *image = ASGraphicsGetImageAndEndCurrentContext();
return image;
}

Expand Down
1 change: 1 addition & 0 deletions Source/AsyncDisplayKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
#import <AsyncDisplayKit/UIView+ASConvenience.h>
#import <AsyncDisplayKit/UIImage+ASConvenience.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>
#import <AsyncDisplayKit/NSArray+Diffing.h>
#import <AsyncDisplayKit/ASObjectDescriptionHelpers.h>
#import <AsyncDisplayKit/UIResponder+AsyncDisplayKit.h>
Expand Down
6 changes: 3 additions & 3 deletions Source/Debug/AsyncDisplayKit+Debug.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#import <AsyncDisplayKit/AsyncDisplayKit+Debug.h>
#import <AsyncDisplayKit/ASAbstractLayoutController.h>
#import <AsyncDisplayKit/ASGraphicsContext.h>
#import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASWeakSet.h>
#import <AsyncDisplayKit/UIImage+ASConvenience.h>
Expand Down Expand Up @@ -148,16 +149,15 @@ - (void)layout
UIColor *clipsBorderColor = [UIColor colorWithRed:30/255.0 green:90/255.0 blue:50/255.0 alpha:0.7];
CGRect imgRect = CGRectMake(0, 0, 2.0 * borderWidth + 1.0, 2.0 * borderWidth + 1.0);

UIGraphicsBeginImageContext(imgRect.size);
ASGraphicsBeginImageContextWithOptions(imgRect.size, NO, 1);

[fillColor setFill];
UIRectFill(imgRect);

[self drawEdgeIfClippedWithEdges:clippedEdges color:clipsBorderColor borderWidth:borderWidth imgRect:imgRect];
[self drawEdgeIfClippedWithEdges:clipsToBoundsClippedEdges color:borderColor borderWidth:borderWidth imgRect:imgRect];

UIImage *debugHighlightImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *debugHighlightImage = ASGraphicsGetImageAndEndCurrentContext();

UIEdgeInsets edgeInsets = UIEdgeInsetsMake(borderWidth, borderWidth, borderWidth, borderWidth);
debugOverlay.image = [debugHighlightImage resizableImageWithCapInsets:edgeInsets resizingMode:UIImageResizingModeStretch];
Expand Down
62 changes: 62 additions & 0 deletions Source/Details/ASGraphicsContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// ASGraphicsContext.h
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <CoreGraphics/CoreGraphics.h>

@class UIImage;

/**
* Functions for creating one-shot graphics contexts that do not have to copy
* their contents when an image is generated from them. This is efficient
* for our use, since we do not reuse graphics contexts.
*
* The API mirrors the UIGraphics API, with the exception that forming an image
* ends the context as well.
*/

NS_ASSUME_NONNULL_BEGIN
ASDISPLAYNODE_EXTERN_C_BEGIN

/**
* Call this to enable the experimental no-copy rendering.
*
* Returns YES if it was enabled, or NO + assert if it's too late because
* rendering has already started. In practice it's fine to call this
* during -didFinishLaunchingWithOptions:.
*/
extern BOOL ASEnableNoCopyRendering(void);

/**
* Creates a one-shot context.
*
* Behavior is the same as UIGraphicsBeginImageContextWithOptions.
*/
extern void ASGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);

/**
* Generates and image and ends the current one-shot context.
*
* Behavior is the same as UIGraphicsGetImageFromCurrentImageContext followed by UIGraphicsEndImageContext.
*/
extern UIImage * _Nullable ASGraphicsGetImageAndEndCurrentContext(void);

/**
* Call this if you want to end the current context without making an image.
*
* Behavior is the same as UIGraphicsEndImageContext.
*/
extern void ASGraphicsEndImageContext(void);

ASDISPLAYNODE_EXTERN_C_END
NS_ASSUME_NONNULL_END
Loading