mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-24 22:33:52 +03:00
Add a flag for parallel rendering
This commit is contained in:
parent
05c351c09e
commit
653026720b
@ -20,6 +20,8 @@ final class AttributesRunDrawer {
|
||||
}
|
||||
|
||||
var usesLigatures: Bool
|
||||
var drawsParallel = false
|
||||
|
||||
private(set) var cellSize: CGSize = .zero
|
||||
private(set) var baselineOffset: CGFloat = 0
|
||||
private(set) var descent: CGFloat = 0
|
||||
@ -40,15 +42,11 @@ final class AttributesRunDrawer {
|
||||
offset: CGPoint,
|
||||
`in` context: CGContext
|
||||
) {
|
||||
#if DEBUG
|
||||
self.drawByParallelComputation(
|
||||
attrsRuns,
|
||||
defaultAttributes: defaultAttributes,
|
||||
offset: offset,
|
||||
in: context
|
||||
)
|
||||
#else
|
||||
let runs = attrsRuns.map { self.fontGlyphRuns(from: $0, offset: offset) }
|
||||
let runs = self.drawsParallel ?
|
||||
attrsRuns.parallelMap(chunkSize: 50) { run in
|
||||
self.fontGlyphRuns(from: run, offset: offset)
|
||||
}
|
||||
: attrsRuns.map { self.fontGlyphRuns(from: $0, offset: offset) }
|
||||
|
||||
for i in 0..<attrsRuns.count {
|
||||
self.draw(
|
||||
@ -58,9 +56,10 @@ final class AttributesRunDrawer {
|
||||
in: context
|
||||
)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private let typesetter = Typesetter()
|
||||
|
||||
private func draw(
|
||||
_ run: AttributesRun,
|
||||
fontGlyphRuns: [FontGlyphRun],
|
||||
@ -144,8 +143,6 @@ final class AttributesRunDrawer {
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
private let typesetter = Typesetter()
|
||||
|
||||
private func draw(
|
||||
backgroundFor run: AttributesRun,
|
||||
with defaultAttributes: CellAttributes,
|
||||
@ -196,27 +193,6 @@ final class AttributesRunDrawer {
|
||||
return fontGlyphRuns
|
||||
}
|
||||
|
||||
private func drawByParallelComputation(
|
||||
_ attrsRuns: [AttributesRun],
|
||||
defaultAttributes: CellAttributes,
|
||||
offset: CGPoint,
|
||||
`in` context: CGContext
|
||||
) {
|
||||
var result = Array(repeating: [FontGlyphRun](), count: attrsRuns.count)
|
||||
DispatchQueue.concurrentPerform(iterations: attrsRuns.count) { i in
|
||||
result[i] = self.fontGlyphRuns(from: attrsRuns[i], offset: offset)
|
||||
}
|
||||
|
||||
attrsRuns.enumerated().forEach { (i, attrsRun) in
|
||||
self.draw(
|
||||
attrsRun,
|
||||
fontGlyphRuns: result[i],
|
||||
defaultAttributes: defaultAttributes,
|
||||
in: context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateFontMetrics() {
|
||||
self.cellSize = FontUtils.cellSize(
|
||||
of: self.font, linespacing: self.linespacing
|
||||
|
@ -139,6 +139,12 @@ public class NvimView: NSView,
|
||||
}
|
||||
}
|
||||
|
||||
public var drawsParallel = false {
|
||||
didSet {
|
||||
self.drawer.drawsParallel = self.drawsParallel
|
||||
}
|
||||
}
|
||||
|
||||
public var linespacing: CGFloat {
|
||||
get {
|
||||
return self._linespacing
|
||||
|
@ -16,6 +16,36 @@ extension Array where Element: Hashable {
|
||||
|
||||
extension RandomAccessCollection where Index == Int {
|
||||
|
||||
func parallelMap<T>(
|
||||
chunkSize: Int = 1,
|
||||
_ transform: @escaping (Element) -> T
|
||||
) -> [T] {
|
||||
let count = self.count
|
||||
guard count > chunkSize else { return self.map(transform) }
|
||||
|
||||
var result = Array<T?>(repeating: nil, count: count)
|
||||
|
||||
// If we don't use Array.withUnsafeMutableBufferPointer,
|
||||
// then we get crashes.
|
||||
result.withUnsafeMutableBufferPointer { pointer in
|
||||
if chunkSize == 1 {
|
||||
DispatchQueue.concurrentPerform(iterations: count) { i in
|
||||
pointer[i] = transform(self[i])
|
||||
}
|
||||
} else {
|
||||
let chunkCount = Int(ceil(Double(self.count) / Double(chunkSize)))
|
||||
DispatchQueue.concurrentPerform(iterations: chunkCount) { chunkIndex in
|
||||
let start = Swift.min(chunkIndex * chunkSize, count)
|
||||
let end = Swift.min(start + chunkSize, count)
|
||||
|
||||
(start..<end).forEach { i in pointer[i] = transform(self[i]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.map { $0! }
|
||||
}
|
||||
|
||||
func groupedRanges<T: Equatable>(
|
||||
with marker: (Index, Element) -> T
|
||||
) -> [CountableClosedRange<Index>] {
|
||||
|
@ -17,7 +17,11 @@ class AdvancedPrefReducer: ReducerType {
|
||||
|
||||
case let .setUseLiveResize(value):
|
||||
state.mainWindowTemplate.useLiveResize = value
|
||||
state.mainWindows.keys.forEach { state.mainWindows[$0]?.useLiveResize = value }
|
||||
state.mainWindows.keys.forEach { state.mainWindows[$0]?.useLiveResize = value }
|
||||
|
||||
case let .setDrawsParallel(value):
|
||||
state.mainWindowTemplate.drawsParallel = value
|
||||
state.mainWindows.keys.forEach { state.mainWindows[$0]?.drawsParallel = value }
|
||||
|
||||
case let .setTrackpadScrollResistance(value):
|
||||
state.mainWindowTemplate.trackpadScrollResistance = value
|
||||
|
@ -17,6 +17,7 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
case setUseSnapshotUpdate(Bool)
|
||||
case setTrackpadScrollResistance(Double)
|
||||
case setUseLiveResize(Bool)
|
||||
case setDrawsParallel(Bool)
|
||||
}
|
||||
|
||||
override var displayName: String {
|
||||
@ -34,6 +35,7 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
self.useSnapshotUpdate = state.useSnapshotUpdate
|
||||
self.sensitivity = 1 / state.mainWindowTemplate.trackpadScrollResistance
|
||||
self.useLiveResize = state.mainWindowTemplate.useLiveResize
|
||||
self.drawsParallel = state.mainWindowTemplate.drawsParallel
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
@ -63,11 +65,13 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
private var useInteractiveZsh: Bool
|
||||
private var useSnapshotUpdate: Bool
|
||||
private var useLiveResize: Bool
|
||||
private var drawsParallel: Bool
|
||||
private var sensitivity: Double
|
||||
|
||||
private let useInteractiveZshCheckbox = NSButton(forAutoLayout: ())
|
||||
private let useSnapshotUpdateCheckbox = NSButton(forAutoLayout: ())
|
||||
private let useLiveResizeCheckbox = NSButton(forAutoLayout: ())
|
||||
private let drawsParallelCheckbox = NSButton(forAutoLayout: ())
|
||||
private let sensitivitySlider = NSSlider(forAutoLayout: ())
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -78,6 +82,7 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
self.useSnapshotUpdateCheckbox.boolState = self.useSnapshotUpdate
|
||||
self.useInteractiveZshCheckbox.boolState = self.useInteractiveZsh
|
||||
self.useLiveResizeCheckbox.boolState = self.useLiveResize
|
||||
self.drawsParallelCheckbox.boolState = self.drawsParallel
|
||||
|
||||
// We don't update the value of the NSSlider since we don't know when events are fired.
|
||||
}
|
||||
@ -108,7 +113,7 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
""")
|
||||
|
||||
let useLiveResize = self.useLiveResizeCheckbox
|
||||
self.configureCheckbox(button: self.useLiveResizeCheckbox,
|
||||
self.configureCheckbox(button: useLiveResize,
|
||||
title: "Use Live Window Resizing",
|
||||
action: #selector(AdvancedPref.useLiveResizeAction(_:)))
|
||||
|
||||
@ -117,6 +122,18 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
If you do, please report them at [GitHub](https://github.com/qvacua/vimr/issues).
|
||||
""")
|
||||
|
||||
let drawsParallelBox = self.drawsParallelCheckbox
|
||||
self.configureCheckbox(button: drawsParallelBox,
|
||||
title: "Use Concurrent Rendering",
|
||||
action: #selector(AdvancedPref.drawParallelAction(_:)))
|
||||
|
||||
let drawsParallelInfo = self.infoTextField(
|
||||
markdown: """
|
||||
VimR can compute the glyphs concurrently. This will result in faster rendering,
|
||||
but also in higher CPU usage when scrolling very fast.
|
||||
"""
|
||||
)
|
||||
|
||||
let sensitivityTitle = self.titleTextField(title: "Scroll Sensitivity:")
|
||||
let sensitivity = self.sensitivitySlider
|
||||
sensitivity.maxValue = 1 / 5.0
|
||||
@ -142,6 +159,8 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
self.addSubview(sensitivityInfo)
|
||||
self.addSubview(useLiveResize)
|
||||
self.addSubview(useLiveResizeInfo)
|
||||
self.addSubview(drawsParallelBox)
|
||||
self.addSubview(drawsParallelInfo)
|
||||
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
@ -165,7 +184,14 @@ class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
useLiveResizeInfo.autoPinEdge(.left, to: .left, of: useLiveResize)
|
||||
useLiveResizeInfo.autoSetDimension(.width, toSize: 300)
|
||||
|
||||
useSnapshotUpdate.autoPinEdge(.top, to: .bottom, of: useLiveResizeInfo, withOffset: 18)
|
||||
drawsParallelBox.autoPinEdge(.top, to: .bottom, of: useLiveResizeInfo, withOffset: 18)
|
||||
drawsParallelBox.autoPinEdge(.left, to: .right, of: sensitivityTitle, withOffset: 5)
|
||||
|
||||
drawsParallelInfo.autoPinEdge(.top, to: .bottom, of: drawsParallelBox, withOffset: 5)
|
||||
drawsParallelInfo.autoPinEdge(.left, to: .left, of: drawsParallelBox)
|
||||
drawsParallelInfo.autoSetDimension(.width, toSize: 300)
|
||||
|
||||
useSnapshotUpdate.autoPinEdge(.top, to: .bottom, of: drawsParallelInfo, withOffset: 18)
|
||||
useSnapshotUpdate.autoPinEdge(.left, to: .right, of: sensitivityTitle, withOffset: 5)
|
||||
|
||||
useSnapshotUpdateInfo.autoPinEdge(.top, to: .bottom, of: useSnapshotUpdate, withOffset: 5)
|
||||
@ -188,6 +214,10 @@ extension AdvancedPref {
|
||||
self.emit(.setUseLiveResize(sender.boolState))
|
||||
}
|
||||
|
||||
@objc func drawParallelAction(_ sender: NSButton) {
|
||||
self.emit(.setDrawsParallel(sender.boolState))
|
||||
}
|
||||
|
||||
@objc func sensitivitySliderAction(_ sender: NSSlider) {
|
||||
self.emit(.setTrackpadScrollResistance(1 / sender.doubleValue))
|
||||
}
|
||||
|
@ -263,6 +263,7 @@ extension MainWindow {
|
||||
|
||||
var trackpadScrollResistance = 5.0
|
||||
var useLiveResize = false
|
||||
var drawsParallel = false
|
||||
|
||||
var isTemporarySession = false
|
||||
|
||||
@ -308,6 +309,7 @@ extension MainWindow {
|
||||
case trackpadScrollResistance = "trackpad-scroll-resistance"
|
||||
case useInteractiveZsh = "use-interactive-zsh"
|
||||
case useLiveResize = "use-live-resize"
|
||||
case drawsParallel = "draws-parallel"
|
||||
case isShowHidden = "is-show-hidden"
|
||||
|
||||
case appearance = "appearance"
|
||||
@ -326,6 +328,7 @@ extension MainWindow {
|
||||
self.trackpadScrollResistance = try container.decode(forKey: .trackpadScrollResistance,
|
||||
default: State.default.trackpadScrollResistance)
|
||||
self.useLiveResize = try container.decode(forKey: .useLiveResize, default: State.default.useLiveResize)
|
||||
self.drawsParallel = try container.decode(forKey: .drawsParallel, default: State.default.drawsParallel)
|
||||
if let frameRawValue = try container.decodeIfPresent(String.self, forKey: .frame) {
|
||||
self.frame = NSRectFromString(frameRawValue)
|
||||
} else {
|
||||
@ -380,6 +383,7 @@ extension MainWindow {
|
||||
try container.encode(NSStringFromRect(self.frame), forKey: .frame)
|
||||
try container.encode(self.trackpadScrollResistance, forKey: .trackpadScrollResistance)
|
||||
try container.encode(self.useLiveResize, forKey: .useLiveResize)
|
||||
try container.encode(self.drawsParallel, forKey: .drawsParallel)
|
||||
try container.encode(self.isLeftOptionMeta, forKey: .isLeftOptionMeta)
|
||||
try container.encode(self.isRightOptionMeta, forKey: .isRightOptionMeta)
|
||||
try container.encode(self.useInteractiveZsh, forKey: .useInteractiveZsh)
|
||||
|
Loading…
Reference in New Issue
Block a user