Skip to content
This repository has been archived by the owner on Sep 23, 2019. It is now read-only.

Commit

Permalink
Boost drawing performance w/ proper use of setNeedsDisplayInRect
Browse files Browse the repository at this point in the history
  • Loading branch information
rofreg committed Jul 2, 2016
1 parent f2c17db commit 1677a01
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
25 changes: 19 additions & 6 deletions PinchPad/Canvas.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@ class Canvas: UIView {

// Only redraw the active stroke once every .05s or so
if (!self.activeStroke!.isDot()){
self.setNeedsDisplay()
self.setNeedsDisplayInRect(activeStroke!.rect)
}
}

func strokeEnded(atPoint point: CGPoint, withPressure pressure: CGFloat? = nil){
addPointToActiveStroke(point, pressure: pressure)
strokes.append(self.activeStroke!)
let oldActiveStroke = self.activeStroke
self.activeStroke = nil
self.setNeedsDisplay()
self.setNeedsDisplayInRect(oldActiveStroke!.rect)
}

func strokeCancelled(){
Expand Down Expand Up @@ -152,13 +153,22 @@ class Canvas: UIView {
// MARK: Rendering

override func drawRect(rect: CGRect) {
let screenScale = UIScreen.mainScreen().scale
let scaledRect = CGRectMake(rect.minX*screenScale, rect.minY*screenScale, rect.size.width*screenScale, rect.size.height*screenScale)

// We're gonna save everything to a cached UIImage
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)

if let stroke = activeStroke{
// Draw just the latest line segment
if let cachedImage = canvasThusFar {
cachedImage.drawInRect(rect)
// When possible, draw a cropped segment for better performance
// This doesn't fully work yet – it fails to draw bg stuff during an active stroke
let imageRef = CGImageCreateWithImageInRect(cachedImage.CGImage, scaledRect)
let croppedImageThusFar = UIImage(CGImage:imageRef!)
croppedImageThusFar.drawInRect(rect)

// cachedImage.drawInRect(self.bounds)
} else {
CGContextClearRect(UIGraphicsGetCurrentContext(), self.bounds)
}
Expand All @@ -168,7 +178,7 @@ class Canvas: UIView {
// Redraw everything up to the last step
CGContextClearRect(UIGraphicsGetCurrentContext(), self.bounds)
if let cachedImage = canvasAfterLastStroke {
cachedImage.drawInRect(rect)
cachedImage.drawInRect(self.bounds)

// Draw the most recent stroke in full
if let stroke = strokes.last {
Expand All @@ -192,8 +202,11 @@ class Canvas: UIView {
}

// Draw result to screen
// TODO: this is slow. use a second view as an on-screen buffer?
canvasThusFar!.drawInRect(rect)
// While drawing an active stroke, we crop this to a smaller area for better performance
// This is one of the biggest performance bottlenecks in the app
let imageRef = CGImageCreateWithImageInRect(canvasThusFar!.CGImage, scaledRect)
let croppedImageThusFar = UIImage(CGImage:imageRef!)
croppedImageThusFar.drawInRect(rect)
}
}

Expand Down
15 changes: 15 additions & 0 deletions PinchPad/Stroke.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ class Stroke{
return ToolConfig.sharedInstance.isStylusConnected ? 0.1 : 3
}
}
var rect: CGRect {
get {
guard points.count > 0 else {
return CGRectZero
}

// Return a rect that encompasses all points
let left = points.map{ $0.location.x }.reduce(CGFloat.max){ min($0,$1) } - width
let right = points.map{ $0.location.x }.reduce(CGFloat.min){ max($0,$1) } + width
let top = points.map{ $0.location.y }.reduce(CGFloat.max){ min($0,$1) } - width
let bottom = points.map{ $0.location.y }.reduce(CGFloat.min){ max($0,$1) } + width

return CGRect(x: left, y: top, width: right-left, height: bottom-top)
}
}

required init(width: CGFloat!, color: UIColor!){
self.width = width
Expand Down

0 comments on commit 1677a01

Please sign in to comment.