It happens because QuartzCore has the coordinate system "bottom-left", while UIKit – "top-left".
In the case you can extend CGContext:
extension CGContext {
func changeToTopLeftCoordinateSystem() {
translateBy(x: 0, y: boundingBoxOfClipPath.size.height)
scaleBy(x: 1, y: -1)
}
}
// somewhere in render
ctx.saveGState()
ctx.changeToTopLeftCoordinateSystem()
ctx.draw(cgImage!, in: frame)