Skip to content

Commit

Permalink
Merge #1705 to CGD2D
Browse files Browse the repository at this point in the history
 - 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 committed Jan 25, 2017
1 parent d5a86b9 commit 0ac5491
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 42 deletions.
75 changes: 46 additions & 29 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 @@ -376,6 +377,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 @@ -499,7 +526,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 @@ -572,7 +601,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 @@ -2152,8 +2183,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 @@ -2180,6 +2212,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 @@ -2193,7 +2226,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 @@ -2221,9 +2256,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 @@ -2929,38 +2961,23 @@ CGContextRef _CGBitmapContextCreateWithFormat(int width, int height, __CGSurface
return StubReturn();
}
#pragma endregion

#pragma region CGContextBeginDrawEndDraw

void _CGContextPushBeginDraw(CGContextRef ctx) {
if ((ctx->_beginEndDrawDepth)++ == 0) {
ID2D1RenderTarget* imgRenderTarget = ctx->Backing()->DestImage()->Backing()->GetRenderTarget();
THROW_HR_IF_NULL(E_UNEXPECTED, imgRenderTarget);
imgRenderTarget->BeginDraw();
}
void _CGContextPushBeginDraw(CGContextRef context) {
context->PushBeginDraw();
}

void _CGContextPopEndDraw(CGContextRef ctx) {
if (--(ctx->_beginEndDrawDepth) == 0) {
ID2D1RenderTarget* imgRenderTarget = ctx->Backing()->DestImage()->Backing()->GetRenderTarget();
THROW_HR_IF_NULL(E_UNEXPECTED, imgRenderTarget);
THROW_IF_FAILED(imgRenderTarget->EndDraw());
}
void _CGContextPopEndDraw(CGContextRef context) {
FAIL_FAST_IF_FAILED(context->PopEndDraw());
}

void _CGContextEscapeBeginEndDrawStack(CGContextRef ctx) {
if ((ctx->_beginEndDrawDepth > 0) && ((ctx->_escapeBeginEndDrawDepth)++ == 0)) {
ID2D1RenderTarget* imgRenderTarget = ctx->Backing()->DestImage()->Backing()->GetRenderTarget();
THROW_HR_IF_NULL(E_UNEXPECTED, imgRenderTarget);
THROW_IF_FAILED(imgRenderTarget->EndDraw());
}
void _CGContextEscapeBeginEndDrawStack(CGContextRef context) {
FAIL_FAST_IF_FAILED(context->EscapeBeginEndDrawStack());
}

void _CGContextUnescapeBeginEndDrawStack(CGContextRef ctx) {
if ((ctx->_beginEndDrawDepth > 0) && (--(ctx->_escapeBeginEndDrawDepth) == 0)) {
ID2D1RenderTarget* imgRenderTarget = ctx->Backing()->DestImage()->Backing()->GetRenderTarget();
THROW_HR_IF_NULL(E_UNEXPECTED, imgRenderTarget);
imgRenderTarget->BeginDraw();
}
void _CGContextUnescapeBeginEndDrawStack(CGContextRef context) {
context->UnescapeBeginEndDrawStack();
}

#pragma endregion
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
2 changes: 0 additions & 2 deletions Frameworks/include/CGContextInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ COREGRAPHICS_EXPORT void _CGContextPopEndDraw(CGContextRef ctx);
// For scenarios where a Begin/EndDraw pair needs to be temporarily escaped, to be returned to at a later time
// Ie:
// - Switching render targets - Illegal to do so if currently in a Begin/EndDraw pair
// - Cairo - ID2D1RenderTarget is considered to 'own' the bitmap during Begin/EndDraw,
// unsafe to edit the same bitmap from cairo at this time
// Also counts in a stack-like manner, so that the escape and unescape only happen once
COREGRAPHICS_EXPORT void _CGContextEscapeBeginEndDrawStack(CGContextRef ctx);
COREGRAPHICS_EXPORT void _CGContextUnescapeBeginEndDrawStack(CGContextRef ctx);

0 comments on commit 0ac5491

Please sign in to comment.