Skip to content

Commit

Permalink
Merge #1705 to CGD2D (#1750)
Browse files Browse the repository at this point in the history
* CoreText Performance: Call ID2D1RenderTarget::BeginDraw()/EndDraw() f… (#1705)

* CoreText Performance: Call ID2D1RenderTarget::BeginDraw()/EndDraw() fewer times

Fixes #1620

* - Added Begin/EndDraw pairs to a few more places
- Mitigated an issue with cairo where ID2D1RenderTarget would sometimes cache a before state during begin draw,
  and wipe out any changes cairo made, breaking APIs like CGContextFillRect.
- Changed implementation/naming of the 'escape the current begin/end draw stack' functions

* Merge #1705 to CGD2D
 - Add PushBeginDraw/PopEndDraw pairs to UISegment, UIImage
   (not on develop since this likely would've actually hurt performance there)
 - Add Escape/Unescape pairs to CGContext areas where the target is changed

Fixes #1635

cr feedback

cr feedback
  • Loading branch information
ms-jihua authored Jan 25, 2017
1 parent 30c60dc commit 795c98c
Show file tree
Hide file tree
Showing 16 changed files with 176 additions and 44 deletions.
69 changes: 64 additions & 5 deletions Frameworks/CoreGraphics/CGContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#import <wrl/client.h>
#include <COMIncludes_end.h>

#import <atomic>
#import <list>
#import <vector>
#import <stack>
Expand Down Expand Up @@ -258,6 +259,13 @@ inline HRESULT GetTarget(ID2D1Image** pTarget) {
woc::unique_cf<CGColorSpaceRef> _fillColorSpace;
woc::unique_cf<CGColorSpaceRef> _strokeColorSpace;

// Keeps track of the depth of a 'stack' of PushBeginDraw/PopEndDraw calls
// Since nothing needs to actually be put on a stack, just increment a counter insteads
std::atomic_uint32_t _beginEndDrawDepth = { 0 };

// Keeps track of the depth of a 'stack' of (Un)EscapeBeginEndDrawStack calls
std::atomic_uint32_t _escapeBeginEndDrawDepth = { 0 };

inline HRESULT _SaveD2DDrawingState(ID2D1DrawingStateBlock** pDrawingState) {
RETURN_HR_IF(E_POINTER, !pDrawingState);

Expand Down Expand Up @@ -380,6 +388,32 @@ inline bool ShouldDraw() {
return CurrentGState().ShouldDraw();
}

inline void PushBeginDraw() {
if ((_beginEndDrawDepth)++ == 0) {
deviceContext->BeginDraw();
}
}

inline HRESULT PopEndDraw() {
if (--(_beginEndDrawDepth) == 0) {
RETURN_IF_FAILED(deviceContext->EndDraw());
}
return S_OK;
}

inline HRESULT EscapeBeginEndDrawStack() {
if ((_beginEndDrawDepth > 0) && ((_escapeBeginEndDrawDepth)++ == 0)) {
RETURN_IF_FAILED(deviceContext->EndDraw());
}
return S_OK;
}

inline void UnescapeBeginEndDrawStack() {
if ((_beginEndDrawDepth > 0) && (--(_escapeBeginEndDrawDepth) == 0)) {
deviceContext->BeginDraw();
}
}

HRESULT Clip(CGPathDrawingMode pathMode);

HRESULT PushLayer(CGRect* rect = nullptr);
Expand Down Expand Up @@ -503,7 +537,9 @@ void CGContextSynchronize(CGContextRef context) {
ComPtr<ID2D1CommandList> commandList;
RETURN_IF_FAILED(deviceContext->CreateCommandList(&commandList));

EscapeBeginEndDrawStack();
deviceContext->SetTarget(commandList.Get());
UnescapeBeginEndDrawStack();

// Copy the current layer's state to the new layer.
auto& oldLayer = _layerStack.top();
Expand Down Expand Up @@ -576,7 +612,9 @@ void CGContextSynchronize(CGContextRef context) {
ComPtr<ID2D1Image> incomingImageTarget;
RETURN_IF_FAILED(incomingLayer.GetTarget(&incomingImageTarget));

EscapeBeginEndDrawStack();
deviceContext->SetTarget(incomingImageTarget.Get());
UnescapeBeginEndDrawStack();

RETURN_IF_FAILED(DrawImage(outgoingCommandList.Get()));

Expand Down Expand Up @@ -2156,8 +2194,9 @@ void CGContextClearRect(CGContextRef context, CGRect rect) {
ComPtr<ID2D1CommandList> commandList;
RETURN_IF_FAILED(deviceContext->CreateCommandList(&commandList));

deviceContext->BeginDraw();
EscapeBeginEndDrawStack();
deviceContext->SetTarget(commandList.Get());
deviceContext->BeginDraw();

CGAffineTransform transform = CGAffineTransformIdentity;
switch (coordinateMode) {
Expand All @@ -2184,6 +2223,7 @@ void CGContextClearRect(CGContextRef context, CGRect rect) {
RETURN_IF_FAILED(commandList->Close());

deviceContext->SetTarget(originalTarget.Get());
UnescapeBeginEndDrawStack();

*outCommandList = commandList.Detach();
return S_OK;
Expand All @@ -2197,7 +2237,9 @@ void CGContextClearRect(CGContextRef context, CGRect rect) {
return S_OK;
}

deviceContext->BeginDraw();
PushBeginDraw();
// TODO GH#1194: We will need to re-evaluate Direct2D's D2DERR_RECREATE when we move to HW acceleration.
auto popEnd = wil::ScopeExit([this]() { this->PopEndDraw(); });

bool layer = false;
if (state.clippingGeometry || !IS_NEAR(state.globalAlpha, 1.0, .0001f) || state.opacityBrush) {
Expand Down Expand Up @@ -2225,9 +2267,6 @@ void CGContextClearRect(CGContextRef context, CGRect rect) {
deviceContext->PopLayer();
}

// TODO GH#1194: We will need to re-evaluate Direct2D's D2DERR_RECREATE when we move to HW acceleration.
RETURN_IF_FAILED(deviceContext->EndDraw());

return S_OK;
}

Expand Down Expand Up @@ -2933,3 +2972,23 @@ CGContextRef _CGBitmapContextCreateWithFormat(int width, int height, __CGSurface
return StubReturn();
}
#pragma endregion

#pragma region CGContextBeginDrawEndDraw

void _CGContextPushBeginDraw(CGContextRef context) {
context->PushBeginDraw();
}

void _CGContextPopEndDraw(CGContextRef context) {
FAIL_FAST_IF_FAILED(context->PopEndDraw());
}

void _CGContextEscapeBeginEndDrawStack(CGContextRef context) {
FAIL_FAST_IF_FAILED(context->EscapeBeginEndDrawStack());
}

void _CGContextUnescapeBeginEndDrawStack(CGContextRef context) {
context->UnescapeBeginEndDrawStack();
}

#pragma endregion
4 changes: 4 additions & 0 deletions Frameworks/CoreText/CTFrame.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#import "DWriteWrapper_CoreText.h"
#import "CoreTextInternal.h"
#import "CGContextInternal.h"
#import "CGPathInternal.h"

const CFStringRef kCTFrameProgressionAttributeName = static_cast<CFStringRef>(@"kCTFrameProgressionAttributeName");
Expand Down Expand Up @@ -122,6 +123,9 @@ void CTFrameDraw(CTFrameRef frameRef, CGContextRef ctx) {
ctx, CGAffineTransformMake(textMatrix.a, -textMatrix.b, textMatrix.c, -textMatrix.d, textMatrix.tx, textMatrix.ty));
CGContextScaleCTM(ctx, 1.0f, -1.0f);

_CGContextPushBeginDraw(ctx);
auto popEnd = wil::ScopeExit([ctx]() { _CGContextPopEndDraw(ctx); });

for (size_t i = 0; i < frame->_lineOrigins.size() && (frame->_lineOrigins[i].y < frame->_frameRect.size.height); ++i) {
_CTLine* line = static_cast<_CTLine*>([frame->_lines objectAtIndex:i]);
CGContextSetTextPosition(ctx, frame->_lineOrigins[i].x, frame->_lineOrigins[i].y);
Expand Down
3 changes: 3 additions & 0 deletions Frameworks/CoreText/CTLine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ void CTLineDraw(CTLineRef lineRef, CGContextRef ctx) {

_CTLine* line = static_cast<_CTLine*>(lineRef);

_CGContextPushBeginDraw(ctx);
auto popEnd = wil::ScopeExit([ctx]() { _CGContextPopEndDraw(ctx); });

for (size_t i = 0; i < [line->_runs count]; ++i) {
_CTRun* curRun = [line->_runs objectAtIndex:i];
if (i > 0) {
Expand Down
33 changes: 25 additions & 8 deletions Frameworks/QuartzCore/CALayer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,13 @@ - (void)renderInContext:(CGContextRef)ctx {
[self layoutIfNeeded];

CGContextSaveGState(ctx);
_CGContextPushBeginDraw(ctx);

auto popEnd = wil::ScopeExit([ctx]() {
_CGContextPopEndDraw(ctx);
CGContextRestoreGState(ctx);
});

CGContextTranslateCTM(ctx, priv->position.x, priv->position.y);
CGContextTranslateCTM(ctx, -priv->bounds.size.width * priv->anchorPoint.x, -priv->bounds.size.height * priv->anchorPoint.y);
CGRect destRect;
Expand Down Expand Up @@ -435,8 +442,6 @@ - (void)renderInContext:(CGContextRef)ctx {
LLTREE_FOREACH(curLayer, priv) {
[curLayer->self renderInContext:ctx];
}

CGContextRestoreGState(ctx);
}

/**
Expand Down Expand Up @@ -521,6 +526,13 @@ - (void)display {
CGImageRef target = CGBitmapContextGetImage(drawContext);

CGContextRetain(drawContext);
_CGContextPushBeginDraw(drawContext);

auto popEnd = wil::ScopeExit([drawContext]() {
_CGContextPopEndDraw(drawContext);
CGContextRelease(drawContext);
});

CGImageRetain(target);
priv->savedContext = drawContext;

Expand Down Expand Up @@ -561,7 +573,6 @@ - (void)display {
}

CGContextReleaseLock(drawContext);
CGContextRelease(drawContext);

// If we've drawn anything, set it as our contents
if (!CGContextIsDirty(drawContext)) {
Expand Down Expand Up @@ -2371,7 +2382,7 @@ CGPoint _legacyConvertPoint(CGPoint point, CALayer* fromLayer, CALayer* toLayer)
// Convert the point to center-based position
point.x -= fromLayer->priv->bounds.size.width * fromLayer->priv->anchorPoint.x;
point.y -= fromLayer->priv->bounds.size.height * fromLayer->priv->anchorPoint.y;

// Convert to world-view
CGAffineTransform fromTransform;
GetLayerTransform(fromLayer, &fromTransform);
Expand All @@ -2381,11 +2392,11 @@ CGPoint _legacyConvertPoint(CGPoint point, CALayer* fromLayer, CALayer* toLayer)
GetLayerTransform(toLayer, &toTransform);
toTransform = CGAffineTransformInvert(toTransform);
point = CGPointApplyAffineTransform(point, toTransform);

// Convert the point from center-based position
point.x += toLayer->priv->bounds.size.width * toLayer->priv->anchorPoint.x;
point.y += toLayer->priv->bounds.size.height * toLayer->priv->anchorPoint.y;

return point;
}

Expand Down Expand Up @@ -2439,10 +2450,16 @@ + (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer*)fromLayer toLayer:(CA
// How does our new convertPoint logic compare to the legacy logic?
CGPoint legacyPoint = _legacyConvertPoint(point, fromLayer, toLayer);
if (!_floatAlmostEqual(ret.x, legacyPoint.x) || !_floatAlmostEqual(ret.y, legacyPoint.y)) {
TraceWarning(TAG, L"convertPoint: The legacy point {%f, %f} did not match the new point {%f, %f}!", legacyPoint.x, legacyPoint.y, ret.x, ret.y);
TraceWarning(TAG,
L"convertPoint: The legacy point {%f, %f} did not match the new point {%f, %f}!",
legacyPoint.x,
legacyPoint.y,
ret.x,
ret.y);
}

TraceVerbose(TAG, L"convertPoint:{%f, %f} to:{%f, %f}, legacyPoint={%f, %f}", point.x, point.y, ret.x, ret.y, legacyPoint.x, legacyPoint.y);
TraceVerbose(
TAG, L"convertPoint:{%f, %f} to:{%f, %f}, legacyPoint={%f, %f}", point.x, point.y, ret.x, ret.y, legacyPoint.x, legacyPoint.y);
}

return ret;
Expand Down
4 changes: 4 additions & 0 deletions Frameworks/UIKit/NSLayoutManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <UIKit/UIGraphics.h>

#include "CoreTextInternal.h"
#include "CGContextInternal.h"

#include <vector>
#include <functional>
Expand Down Expand Up @@ -257,6 +258,9 @@ - (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(CGPoint)position {
CGContextSaveGState(curCtx);
CGContextSetTextMatrix(curCtx, CGAffineTransformMakeScale(1.0f, -1.0f));

_CGContextPushBeginDraw(curCtx);
auto popEnd = wil::ScopeExit([curCtx]() { _CGContextPopEndDraw(curCtx); });

int count = [_ctLines count];
for (int curLine = 0; curLine < count; curLine++) {
CTLineRef line = (CTLineRef)_ctLines[curLine];
Expand Down
3 changes: 3 additions & 0 deletions Frameworks/UIKit/NSString+UIKitAdditions.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import <Foundation/NSMutableDictionary.h>
#import "CoreGraphics/CGContext.h"
#import "CoreTextInternal.h"
#import "CGContextInternal.h"
#import "NSParagraphStyleInternal.h"
#import <assert.h>
#import "LoggingNative.h"
Expand Down Expand Up @@ -145,6 +146,8 @@ - (CGSize)drawInRect:(CGRect)rect withFont:(UIFont*)font lineBreakMode:(UILineBr
}

CGContextRef context = UIGraphicsGetCurrentContext();
_CGContextPushBeginDraw(context);
auto popEnd = wil::ScopeExit([context]() { _CGContextPopEndDraw(context); });

// Invert text matrix so glyphs are drawn with correct orientation
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
Expand Down
16 changes: 12 additions & 4 deletions Frameworks/UIKit/UIImage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph
RETURN_IF(!img);

CGContextSaveGState(cur);
_CGContextPushBeginDraw(cur);

auto popEnd = wil::ScopeExit([cur]() {
_CGContextPopEndDraw(cur);
CGContextRestoreGState(cur);
});

CGContextSetBlendMode(cur, mode);
CGContextSetAlpha(cur, alpha);
Expand All @@ -493,8 +499,6 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph
srcRect.size.height = -img_height;

_CGContextDrawImageRect(cur, img, srcRect, pos);

CGContextRestoreGState(cur);
}

/**
Expand Down Expand Up @@ -672,14 +676,18 @@ - (void)drawInRect:(CGRect)pos blendMode:(CGBlendMode)mode alpha:(float)alpha {
}

CGContextSaveGState(ctx);
_CGContextPushBeginDraw(ctx);

auto popEnd = wil::ScopeExit([ctx]() {
_CGContextPopEndDraw(ctx);
CGContextRestoreGState(ctx);
});

CGContextSetBlendMode(ctx, mode);
CGContextSetAlpha(ctx, alpha);

// Draw image and divide into patches if necessary
drawPatches(ctx, self, &pos);

CGContextRestoreGState(ctx);
}

- (void)setOrientation:(UIImageOrientation)orientation {
Expand Down
18 changes: 11 additions & 7 deletions Frameworks/UIKit/UISegment.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#import <UIKit/UIView.h>
#import <Foundation/NSString.h>
#import <CoreGraphics/CGContext.h>
#import "CGContextInternal.h"
#import "UISegment.h"
#import "UIViewInternal.h"
#import "UISegmentedControlInternal.h"
Expand Down Expand Up @@ -224,26 +225,29 @@ - (id)drawRect:(CGRect)inRect {
}
}

CGContextRef ctx = UIGraphicsGetCurrentContext();

_CGContextPushBeginDraw(ctx);
auto popEnd = wil::ScopeExit([ctx]() { _CGContextPopEndDraw(ctx); });

if (isOSTarget(@"7.0")) {
if (_tintColor != nil) {
if (_selected == 1) {
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [_tintColor CGColor]);
CGContextFillRect(UIGraphicsGetCurrentContext(), bounds);
CGContextSetFillColorWithColor(ctx, [_tintColor CGColor]);
CGContextFillRect(ctx, bounds);
}
if ((_type & 2) == 0) {
CGRect rect = bounds;
float lineWidth = 1.0f;

rect.origin.x = rect.size.width - lineWidth;
rect.size.width = lineWidth;
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [_tintColor CGColor]);
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
CGContextSetFillColorWithColor(ctx, [_tintColor CGColor]);
CGContextFillRect(ctx, rect);
}
}
} else {
if (!_noDefaultImages) {
CGContextRef ctx = UIGraphicsGetCurrentContext();

if (_selected) {
// No border, just fill with background color
CGContextSetFillColorWithColor(ctx, [bgColor CGColor]);
Expand Down Expand Up @@ -293,7 +297,7 @@ - (id)drawRect:(CGRect)inRect {
}

if (_title != nil) {
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [textColor CGColor]);
CGContextSetFillColorWithColor(ctx, [textColor CGColor]);

CGSize size;
CGRect rect;
Expand Down
Loading

0 comments on commit 795c98c

Please sign in to comment.