Skip to content

Commit

Permalink
Change targets less in CGContext
Browse files Browse the repository at this point in the history
 - CGContext previously changed targets for all draw primitive functions.
   Since changing targets causes an immediate flush, this significantly negatively impacted performance.
   Changed implementation to only change targets when needed (when shadows are enabled)
 - Added drawing tests for a few edge cases regarding shadows and clipping.
 - Removed unnecessary Escape/Unescape functions - these were not necessary to change targets as previously surmised.

Fixes microsoft#1810
  • Loading branch information
ms-jihua committed Jan 31, 2017
1 parent 7a7d48a commit 1857906
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 251 deletions.
301 changes: 119 additions & 182 deletions Frameworks/CoreGraphics/CGContext.mm

Large diffs are not rendered by default.

10 changes: 1 addition & 9 deletions Frameworks/include/CGContextInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,4 @@ COREGRAPHICS_EXPORT CGImageRef CGBitmapContextGetImage(CGContextRef ctx);
// Reduces the number of BeginDraw() and EndDraw() calls needed, by counting in a stack-like manner,
// and only calling BeginDraw()/EndDraw() when the stack is empty/emptied
COREGRAPHICS_EXPORT void _CGContextPushBeginDraw(CGContextRef ctx);
COREGRAPHICS_EXPORT void _CGContextPopEndDraw(CGContextRef ctx);

// If currently in a Begin/EndDraw stack, Escape will EndDraw(), Unescape will BeginDraw()
// 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
// 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);
COREGRAPHICS_EXPORT void _CGContextPopEndDraw(CGContextRef ctx);
2 changes: 0 additions & 2 deletions build/CoreGraphics/dll/CoreGraphics.def
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,6 @@ LIBRARY CoreGraphics
_CGGetPixelFormatProperties
_CGContextPushBeginDraw
_CGContextPopEndDraw
_CGContextEscapeBeginEndDrawStack
_CGContextUnescapeBeginEndDrawStack

; CGDataConsumer.mm
CGDataConsumerCreate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,53 @@ DISABLED_DRAW_TEST_F(CGContext, ShadowWithRotatedCTM, WhiteBackgroundTest<>) {

CGContextStrokeRect(context, rect);
}

DISABLED_DRAW_TEST_F(CGContext, ShadowOverlap, WhiteBackgroundTest<>) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 5);

CGContextSetShadow(context, CGSize{ 10.f, 10.f }, 1.0);

CGPoint center = _CGRectGetCenter(bounds);
CGRect rect = _CGRectCenteredOnPoint({ 150, 150 }, center);
CGRect rect2 = _CGRectCenteredOnPoint({ 150, 150 }, rect.origin);

CGContextStrokeRect(context, rect);
CGContextStrokeRect(context, rect2);
}

DISABLED_DRAW_TEST_F(CGContext, ShadowEnabledInMiddle, WhiteBackgroundTest<>) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 5);

CGPoint center = _CGRectGetCenter(bounds);
CGRect rect = _CGRectCenteredOnPoint({ 150, 150 }, center);
CGRect rect2 = _CGRectCenteredOnPoint({ 150, 150 }, rect.origin);

CGContextStrokeRect(context, rect);
CGContextSetShadow(context, CGSize{ 10.f, 10.f }, 1.0);
CGContextStrokeRect(context, rect2);
}

DISABLED_DRAW_TEST_F(CGContext, ShadowDisabledInMiddle, WhiteBackgroundTest<>) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 5);

CGPoint center = _CGRectGetCenter(bounds);
CGRect rect = _CGRectCenteredOnPoint({ 150, 150 }, center);
CGRect rect2 = _CGRectCenteredOnPoint({ 150, 150 }, rect.origin);

CGContextSetShadow(context, CGSize{ 10.f, 10.f }, 1.0);
CGContextStrokeRect(context, rect);
CGContextSetShadow(context, CGSize{ 0, 0 }, 0.0);
CGContextStrokeRect(context, rect2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//******************************************************************************
//******************************************************************************

#include "DrawingTest.h"
#include "DrawingTestConfig.h"
Expand Down Expand Up @@ -271,12 +271,12 @@ DRAW_TEST(CGContextClipping, NonOverlappingImageMasks) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

woc::unique_cf<CGImageRef> clipImage{
__CreateClipImage({64, 64}, ClippingTypeAlpha, [](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });
})
};
woc::unique_cf<CGImageRef> clipImage{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });
}) };

CGContextClipToMask(context, { CGPointZero, { 64, 64 } }, clipImage.get());
CGContextClipToMask(context, { { 0, bounds.size.height - 64 }, { 64, 64 } }, clipImage.get());
Expand All @@ -291,12 +291,12 @@ DRAW_TEST(CGContextClipping, CrossTransformedImageMasks) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

woc::unique_cf<CGImageRef> clipImage{
__CreateClipImage({64, 64}, ClippingTypeAlpha, [](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });
})
};
woc::unique_cf<CGImageRef> clipImage{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });
}) };

CGContextClipToMask(context, { CGPointZero, { 64, 64 } }, clipImage.get());
CGContextTranslateCTM(context, 2.0, 2.0);
Expand All @@ -310,19 +310,19 @@ DRAW_TEST(CGContextClipping, PushClipPopClip) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

woc::unique_cf<CGImageRef> clipImage1{
__CreateClipImage({64, 64}, ClippingTypeAlpha, [](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillRect(context, { CGPointZero, size });
})
};
woc::unique_cf<CGImageRef> clipImage1{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillRect(context, { CGPointZero, size });
}) };

woc::unique_cf<CGImageRef> clipImage2{
__CreateClipImage({64, 64}, ClippingTypeAlpha, [](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillEllipseInRect(context, { CGPointZero, size });
})
};
woc::unique_cf<CGImageRef> clipImage2{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillEllipseInRect(context, { CGPointZero, size });
}) };

CGRect clippingRect{ CGPointZero, { 64, 64 } };
CGContextClipToMask(context, clippingRect, clipImage1.get());
Expand All @@ -342,16 +342,49 @@ DRAW_TEST(CGContextClipping, PushClipPopClip) {
CGContextFillRect(context, bounds);
}

DRAW_TEST(CGContextClipping, ClipDrawClipDraw) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

woc::unique_cf<CGImageRef> clipImage1{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillRect(context, { CGPointZero, size });
}) };

woc::unique_cf<CGImageRef> clipImage2{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillEllipseInRect(context, { CGPointZero, size });
}) };

CGRect clippingRect{ CGPointZero, { 64, 64 } };
CGContextClipToMask(context, clippingRect, clipImage1.get());

// This should draw a 50% alpha square.
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, bounds);

CGRect clippingRect2{ { 32, 32 }, { 64, 64 } };
CGContextClipToMask(context, clippingRect2, clipImage2.get());

// This should draw a 25% alpha quarter-circle emanating from one corner of the square.
CGContextSetRGBFillColor(context, 0.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, bounds);
}

DRAW_TEST(CGContextClipping, ClipATransparencyLayer) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

woc::unique_cf<CGImageRef> clipImage{
__CreateClipImage({64, 64}, ClippingTypeAlpha, [](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillRect(context, { CGPointZero, size });
})
};
woc::unique_cf<CGImageRef> clipImage{ __CreateClipImage({ 64, 64 },
ClippingTypeAlpha,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
CGContextFillRect(context, { CGPointZero, size });
}) };

CGRect clippingRect{ CGPointZero, { 64, 64 } };
CGContextClipToMask(context, clippingRect, clipImage.get());
Expand All @@ -376,18 +409,16 @@ DRAW_TEST(CGImage, CreateWithSameSizeMask) {

CGSize imageSize{ static_cast<CGFloat>(CGImageGetWidth(image.get())), static_cast<CGFloat>(CGImageGetHeight(image.get())) };

woc::unique_cf<CGImageRef> alphaMask{
__CreateClipImage(imageSize,
ClippingTypeMask,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });

CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 10.0);
CGContextStrokeRect(context, CGRectInset({ CGPointZero, size }, 20, 20));
})
};
woc::unique_cf<CGImageRef> alphaMask{ __CreateClipImage(imageSize,
ClippingTypeMask,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });

CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 10.0);
CGContextStrokeRect(context, CGRectInset({ CGPointZero, size }, 20, 20));
}) };

ASSERT_NE(nullptr, alphaMask);

Expand All @@ -410,21 +441,19 @@ DRAW_TEST(CGImage, CreateWithScaledMask) {

CGSize imageSize{ static_cast<CGFloat>(CGImageGetWidth(image.get())), static_cast<CGFloat>(CGImageGetHeight(image.get())) };

woc::unique_cf<CGImageRef> alphaMask{
__CreateClipImage({ 64, 64 },
ClippingTypeMask,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });

CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 4.0);
CGPoint points[]{
{ 0, 0 }, { 64, 64 }, { 0, 64 }, { 64, 0 },
};
CGContextStrokeLineSegments(context, points, 4);
})
};
woc::unique_cf<CGImageRef> alphaMask{ __CreateClipImage({ 64, 64 },
ClippingTypeMask,
[](CGContextRef context, CGSize size, ClippingType clipType) {
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, { CGPointZero, size });

CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 4.0);
CGPoint points[]{
{ 0, 0 }, { 64, 64 }, { 0, 64 }, { 64, 0 },
};
CGContextStrokeLineSegments(context, points, 4);
}) };

ASSERT_NE(nullptr, alphaMask);

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1857906

Please sign in to comment.