Core Animation

RSS for tag

Render, compose, and animate visual elements using Core Animation.

Core Animation Documentation

Posts under Core Animation tag

37 Posts
Sort by:
Post not yet marked as solved
0 Replies
599 Views
I’m trying to achieve vertical split view in SwiftUI. There are two views, top one is Map (MKMapView actually, wrapped with UIViewRepresentable) and bottom one for this example could be Color.red. Between them there’s a handle to resize the proportions. Initial proportions are 0.3 of height for bottom, 0.7 for map. When resizing map frame, it feels choppy and slow. Replacing MapView with any other view does not produce the same issue. Issue appears only on my real device (iPhone 11 Pro Max) simulator works fine.
Posted
by dvxiel.
Last updated
.
Post not yet marked as solved
3 Replies
2.3k Views
We have an iOS app in the App Store. Recently, we see in Organizer / Crashes for that app a new type of crash that seems bound to iOS 13 devices (21 devices affected in the last few weeks, all with iOS 13.1, .2, or .3). Xcode reports that the crashes occurred in QuartzCore, on CA::Render::Encoder::grow(unsigned long).Any idea what can it be and how it could be fixed? It doesn't look related to our code. Can it be a recent Apple bug? (We didn't have these crash reports before iOS 13.) Thank you in advance.Here is an extract from the crash log:OS Version: iPhone OS 13.3 (17C54) Release Type: User Baseband Version: n/a Report Version: 104 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Triggered by Thread: 0 Thread 0 name: Thread 0 Crashed: 0 libsystem_kernel.dylib 0x0000000191d27ec4 __pthread_kill + 8 1 libsystem_pthread.dylib 0x0000000191c431d8 pthread_kill$VARIANT$mp + 136 (pthread.c:1458) 2 libsystem_c.dylib 0x0000000191b97844 abort + 100 (abort.c:110) 3 QuartzCore 0x00000001989af340 CA::Render::Encoder::grow(unsigned long) + 304 (render-coding.cpp:562) 4 QuartzCore 0x00000001989afa80 CA::Render::Encoder::encode_data_async(void const*, unsigned long, void (*)(void const*, void*), ... + 172 (render-coding.h:272) 5 QuartzCore 0x000000019886c358 CA::Render::Image::encode(CA::Render::Encoder*) const + 748 (render-image.cpp:401) 6 QuartzCore 0x000000019888510c CA::Render::Layer::encode(CA::Render::Encoder*) const + 112 (render-coding.h:388) 7 QuartzCore 0x00000001989b3c2c CA::Render::encode_set_object(CA::Render::Encoder*, unsigned long, unsigned int, CA::Render::Obje... + 192 (render-coding.cpp:2151) 8 QuartzCore 0x00000001988f78a4 invocation function for block in CA::Context::commit_transaction(CA::Transaction*, double) + 1568 (CAContextInternal.mm:1632) 9 QuartzCore 0x00000001989add88 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 364 (CALayer.mm:2647) 10 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 11 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 12 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 13 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 14 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 15 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 16 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 17 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 18 QuartzCore 0x00000001989add00 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block... + 228 (CALayer.mm:2633) 19 QuartzCore 0x00000001988f6924 CA::Context::commit_transaction(CA::Transaction*, double) + 2872 (CAContextInternal.mm:2288) 20 QuartzCore 0x000000019891fc08 CA::Transaction::commit() + 676 (CATransactionInternal.mm:438) 21 UIKitCore 0x0000000195769698 -[_UIContextBinder updateBindableOrderWithTest:force:] + 704 (_UIContextBinder.m:280) 22 UIKitCore 0x0000000195769214 -[_UIContextBinder createContextsWithTest:creationAction:] + 100 (_UIContextBinder.m:233) 23 UIKitCore 0x00000001961d2510 -[UIWindowScene _prepareForResume] + 84 (UIWindowScene.m:712) 24 UIKitCore 0x00000001955e364c -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 860 (UIScene.m:1055) 25 UIKitCore 0x00000001955e45b8 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 220 (UIScene.m:1315) 26 UIKitCore 0x0000000195b57248 -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 464 (UIApplicationSceneClientAgent.m:80) 27 FrontBoardServices 0x0000000197051248 -[FBSSceneImpl updater:didUpdateSettings:withDiff:transitionContext:completion:] + 544 (FBSSceneImpl.m:551) 28 FrontBoardServices 0x0000000197075d28 __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_bloc... + 120 (FBSWorkspaceScenesClient.m:356) 29 FrontBoardServices 0x000000019705af04 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 232 (FBSWorkspace.m:357) 30 FrontBoardServices 0x0000000197075c5c __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_bloc... + 184 (FBSWorkspaceScenesClient.m:355) 31 libdispatch.dylib 0x0000000191bfd184 _dispatch_client_callout + 16 (object.m:495) 32 libdispatch.dylib 0x0000000191ba5fd8 _dispatch_block_invoke_direct$VARIANT$mp + 224 (queue.c:466) 33 FrontBoardServices 0x000000019709a418 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 40 (FBSSerialQueue.m:173) 34 FrontBoardServices 0x000000019709a0e4 -[FBSSerialQueue _queue_performNextIfPossible] + 404 (FBSSerialQueue.m:216) 35 FrontBoardServices 0x000000019709a60c -[FBSSerialQueue _performNextFromRunLoopSource] + 28 (FBSSerialQueue.m:247) 36 CoreFoundation 0x0000000191eaea00 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 (CFRunLoop.c:1922) 37 CoreFoundation 0x0000000191eae958 __CFRunLoopDoSource0 + 80 (CFRunLoop.c:1956) 38 CoreFoundation 0x0000000191eae0f0 __CFRunLoopDoSources0 + 180 (CFRunLoop.c:1992) 39 CoreFoundation 0x0000000191ea923c __CFRunLoopRun + 1080 (CFRunLoop.c:2882) 40 CoreFoundation 0x0000000191ea8adc CFRunLoopRunSpecific + 464 (CFRunLoop.c:3192) 41 GraphicsServices 0x000000019be2e328 GSEventRunModal + 104 (GSEvent.c:2246) 42 UIKitCore 0x0000000195fa3ae0 UIApplicationMain + 1936 (UIApplication.m:4773) 43 <Our app name> 0x0000000100d9d32c main + 88 (main.m:14) 44 libdyld.dylib 0x0000000191d32360 start + 4
Posted
by sdolhae.
Last updated
.
Post marked as solved
1 Replies
724 Views
I've encountered an animation glitch affecting the text for AxisMarks and AxisLabels in the SwiftUI Chart framework. Below are the sample project code and animated gif for reference: (I'm not being able to attach the gif for some reason. Here's my StackOverflow post with a the gift: https://stackoverflow.com/questions/77007744/swiftui-chart-text-animation-glitch-with-axismarks-and-axislabels) struct ContentView: View { @State var isDisplayingAge = true var body: some View { ChartView(data: ChartDataSample, isDisplayingAge: isDisplayingAge) .onTapGesture { withAnimation { isDisplayingAge.toggle() } } } } struct ChartData: Identifiable { let age: Int let presence: Int let grade: Int let id = UUID() } struct ChartView: View { let data: [ChartData] let isDisplayingAge: Bool let xAxis = [0, 50, 100] var body: some View { VStack { Chart { ForEach(data) { chartData in BarMark(x: .value("X Axis", isDisplayingAge ? chartData.age : chartData.presence), y: .value("Y Axis", chartData.grade)) } } .chartXAxis(content: { AxisMarks(position: .bottom, values: xAxis.map{$0}) { data in AxisValueLabel(String(xAxis[data.index]) + (isDisplayingAge ? " years" : " days")) } }) .chartXAxisLabel(content: { Text(isDisplayingAge ? "Data: age" : "Data: presence") }) } .padding(.horizontal, 13) } } As you can observe, when I tap the chart to trigger a content change with animation, the text for AxisMarks (e.g., x years / x days) and AxisLabels (e.g., Data: age / Data: presence) animates unusually. A portion of the text is temporarily replaced by an ellipsis ("...") during the animation. Interestingly, this issue occurs only in one direction of the animation. When transitioning from "year" to "day" or from "presence" to "age," the text simply gets replaced without any noticeable animation. Can anyone explain what's happening here? Ideally, I'd like the texts to either fade into each other or be replaced without any animation. Thank you.
Posted
by Flict.
Last updated
.
Post not yet marked as solved
0 Replies
504 Views
I want to generate a video from some images and that video should have some animation while changing one image to another. is it possible with UIView.transition(with:duration:options:animations:completion:) ? If it possible, then how can I achieve this ?
Posted
by ashikur16.
Last updated
.
Post not yet marked as solved
0 Replies
557 Views
Wrote a transition code for some images. It can show image one by one. But I want to create a video with this kind of animations (Zoom in, Zoom out etc). How can I achieve this. UIView.transition(with: self.imageView, duration: 2.0, options: .transitionCrossDissolve, animations: { self.imageView.image = UIImage(imageLiteralResourceName: "image2") }, completion: nil)
Posted
by ashikur16.
Last updated
.
Post not yet marked as solved
0 Replies
538 Views
Hi. I'm currently working on a project, where I try to achieve the best possible UX when rendering an interactive scene using custom Metal renderer. The problem I'm facing right now is that from what I've observed, the timing of how touch events (in touchesBegan/Moved/Ended/Cancelled) arrive with regards to DisplayLink callbacks is different on different devices using latest stable iOS. Disregarding special cases (fast touches movement causing two touchesMoved along with a single touchedEnded arriving during a frame interval and having awkward timing), the general picture is this: on 14 Pro: vsync - (8 ms of nothing) - touches - vsync on 11 Pro Max: vsync - touches - (16 ms of nothing) - vsync In order to minimize input-to-presentation latency and fit CPU + GPU work into one frame, I'd like to schedule drawing right when CADisplayLink callback arrives. The problem is that at this point on 11 Pro Max I have no knowledge about whether touches arrive or not, so the best we could do is to process those touches and schedule redraw on next vsync, which causes almost two frames latency between input and draw that reflects changes caused by this input (33 ms) On 14 Pro, touches are dispatched just before next vsync, so the actual latency is just one 120hz frame (8ms). What are possible workarounds to achieve the same UX on iPhone 11 Pro Max?
Posted Last updated
.
Post not yet marked as solved
1 Replies
1.4k Views
I needed an infinite canvas for my app which is basically a drawing board where one can draw things using pen. So, I thought of having a very large custom UIView inside a UIScrollView. And in the custom view, I could keep drawing things. But, I ended up with a warning saying something like below and nothing drawn on screen. [<CALayer: 0x5584190> display]: Ignoring bogus layer size (50000, 50000) Which means, I can't have such a big CALayer to draw things. Now, solution? alternative? Then comes CATiledLayer. I made my large UIView backed by CATiledLayer now. After having a proper levelOfDetails and levelOfDetailsBias value, things worked like charm. Until I ended up facing another problem. Since, CATiledLayer caches drawing in different zoom levels if I try to scale the view after changing the drawing content the cached drawings appear and then the new contents get drawn. I don't find an option to invalidate caches in different levels. All the solutions I came across leads me to clear the entire contents of the CATiledLayer on drawing content change which won't help again. Do I miss something here? Is there a way with which I can clear caches at different levels? Or is there any other solutions which could solve my need? Can someone help me with this?
Posted Last updated
.
Post not yet marked as solved
5 Replies
2.3k Views
Hi! I am currently finalizing a new app that uses Metal to render a 3D scene and a UIKit overlay to display controls for interacting with objects in the scene. The render loop is driven via a CADisplayLink with its preferredFramesPerSecond set to 60. I have recently noticed an issue where the app reports a steady 60 fps frame rate in the Xcode debug navigator, but still felt sluggish on the device. This feeling was only present on devices with ProMotion and often started after interactions with the UIKit overlay. I started investigating by using Metal System Trace and quickly found an explanation for the sluggish feeling: occasionally, the app would switch from its nominal 16ms-16ms-16ms cadence to 12ms-20ms-12ms, thus still averaging 60 fps, but with inconsistent frame times. Pictures of the timeline can be found here. I have tried setting the CAMetalLayer's presentsWithTransaction to true, waiting for the command buffer to be scheduled and then presenting the drawable, but, unfortunately, the problem persists. If anybody can think of a potential reason / solution for this, I would be very thankful.
Posted
by vortycon.
Last updated
.
Post not yet marked as solved
0 Replies
664 Views
I'm writing a multiplatform app that uses MapKit with custom tiles via MKTileOverlay. The map should have buttons for zooming in and out. Those buttons set the region of the MKMapView with animation parameter. I want to make this animation faster. While good for generic change of a region, it feels too slow when changing the region for the zooming purposes. In general, I'm working with SwiftUI. But because MKTileOverlay is not available there, the MKMapView is being accessed via the UIViewRepresentable and NSViewRepresentable respectively. On iOS, to make animation faster (reduce animation time), I'm using UIView.animate(withDuration: 0.2) { mapView.setRegion(region, animated: true) } and it achieves the goal. On macOS, I tried: NSAnimationContext.runAnimationGroup { context in context.duration = 0.2 mapView.setRegion(region, animated: true) } and: CATransaction.begin() CATransaction.setAnimationDuration(0.2) mapView.setRegion(region, animated: true) CATransaction.commit() but without success. The default animation duration is not overridden. I appreciate any input you could give me. Alexey
Posted
by eofster.
Last updated
.
Post not yet marked as solved
0 Replies
529 Views
I'm exploring using the CARemoteLayerClient/Server API to render a layer from another process as is described in the docs, but can't seem to get a very simple example to work. Here's a very simple example of what I'd expect to work: // Run with `swift file.swift` import AppKit let app = NSApplication.shared class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow( contentRect: NSMakeRect(200, 200, 400, 200), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false, screen: nil ) func applicationDidFinishLaunching(_ notification: Notification) { window.makeKeyAndOrderFront(nil) let view = NSView() view.frame = NSRect(x: 0, y: 0, width: 150, height: 150) view.layerUsesCoreImageFilters = true view.wantsLayer = true let server = CARemoteLayerServer.shared() let client = CARemoteLayerClient(serverPort: server.serverPort) print(client.clientId) client.layer = CALayer() client.layer?.backgroundColor = NSColor.red.cgColor // Expect red rectangle client.layer?.bounds = CGRect(x: 0, y: 0, width: 100, height: 100) let serverLayer = CALayer(remoteClientId: client.clientId) serverLayer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100) view.layer?.addSublayer(serverLayer) view.layer?.backgroundColor = NSColor.blue.cgColor // Background blue to confirm parent layer exists window.contentView?.addSubview(view) } } let delegate = AppDelegate() app.delegate = delegate app.run() In this example I'd expect there to be a red rectangle appearing as the remote layer. If I inspect the server's layer hierarchy I see the correct CALayerHost with the correct client ID being created, but it doesn't display the correct contents being set from the client side. After investigating this thread: https://bugs.chromium.org/p/chromium/issues/detail?id=312462 and some demo projects, I've found that the workarounds previously found to make this API work no longer seem to work on my machine (M1 Pro, Ventura). Am I missing something glaringly obvious in my simple implementation or is this a bug?
Posted Last updated
.
Post not yet marked as solved
0 Replies
539 Views
Hi I'm trying to resize my NSPanel with spring animation but I have a position problem (the panel is not on center of screen) when I make the panel bigger (see the video) How can I fix it? Video: https://streamable.com/l4281l func animationBigger () { let jump = CASpringAnimation(keyPath: "transform.scale") jump.damping = 60 jump.mass = 10 jump.initialVelocity = 10 jump.stiffness = 200.0 jump.fromValue = 1.0 jump.toValue = 2.0 jump.duration = 0.4 //self is NSPanel self.contentView?.layer!.add(jump, forKey: nil) self.setContentSize(bignotchSize) } class NotchView: NSView { private var mouseDownSubject = PassthroughSubject<NSPoint, Never>() var mouseDownPublisher: AnyPublisher<NSPoint, Never> { return mouseDownSubject.eraseToAnyPublisher() } //Draw notch override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) drawNotch() } func drawNotch () { self.layer?.anchorPoint = CGPoint(x: 0.0, y: 0.0) let size = self.frame.size let r: CGFloat = 15.0 let gap: CGFloat = 1.0 let notch = NSBezierPath() notch.move(to: NSPoint(x: 0.0, y: size.height)) notch.curve(to: NSPoint(x: r, y: size.height - r), controlPoint1: NSPoint(x: r - gap, y: size.height), controlPoint2: NSPoint(x: r, y: size.height - gap)) notch.line(to: NSPoint(x: r, y: r)) notch.curve(to: NSPoint(x: 2 * r, y: 0.0), controlPoint1: NSPoint(x: r, y: gap), controlPoint2: NSPoint(x: r + gap, y: 0.0)) notch.line(to: NSPoint(x: size.width - 2 * r, y: 0.0)) notch.curve(to: NSPoint(x: size.width - r, y: r), controlPoint1: NSPoint(x: size.width - r - gap, y: 0.0), controlPoint2: NSPoint(x: size.width - r, y: gap)) notch.line(to: NSPoint(x: size.width - r, y: size.height - r)) notch.curve(to: NSPoint(x: size.width, y: size.height), controlPoint1: NSPoint(x: size.width - r, y: size.height - gap), controlPoint2: NSPoint(x: size.width - r + gap, y: size.height)) notch.close() NSColor.black.setFill() //change to black to see the notch notch.fill() }``` ```language class NotchPanel: NSPanel, CAAnimationDelegate { private (set) var notchView = NotchView() var notchClickPublisher: AnyPublisher<NSPoint, Never> { return notchView.mouseDownPublisher } init(_ center: NSPoint,_ size: NSSize) { let notchFrame = NSRect(x: center.x - 0.5 * size.width, y: center.y - size.height, width: size.width, height: size.height) super.init(contentRect: notchFrame, styleMask: [ .nonactivatingPanel,.nonactivatingPanel, .hudWindow], backing: .buffered, defer: true) self.level = .popUpMenu self.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary] self.isOpaque = true self.isMovable = false //Disable notch to be moveable self.hasShadow = false //we do custom shadow later self.backgroundColor = NSColor.systemPink //notch background setNotchView() } private func setNotchView() { self.contentView?.addSubview(notchView) notchView.translatesAutoresizingMaskIntoConstraints = false notchView.leftAnchor .constraint(equalTo: self.contentView!.leftAnchor) .isActive = true notchView.topAnchor .constraint(equalTo: self.contentView!.topAnchor) .isActive = true notchView.rightAnchor .constraint(equalTo: self.contentView!.rightAnchor) .isActive = true notchView.bottomAnchor .constraint(equalTo: self.contentView!.bottomAnchor) .isActive = true }```
Posted
by aviorrok.
Last updated
.
Post not yet marked as solved
1 Replies
792 Views
Hi, I'm trying to resize my rect with CABasicAnimation and the animation go to up and not down How can I change it? Video: https://streamable.com/nw4ekc Thank you! let newFrame = NSRect(x: blueRect.frame.origin.x, y: blueRect.frame.origin.y - 100,width: blueRect.frame.size.width, height: 200) let animation = CABasicAnimation(keyPath: "bounds") animation.fromValue = NSValue(rect: blueRect.frame) animation.toValue = NSValue(rect: newFrame) animation.duration = 0.5 // Animation duration in seconds blueRect.layer?.add(animation, forKey: "sizeAnimation") // Update the rect view's size and origin blueRect.frame = newFrame
Posted
by aviorrok.
Last updated
.
Post not yet marked as solved
0 Replies
1k Views
Hello there! We do have a (custom, borderless) NSWindow which is moved / resized by app methods, not standard window-titlebar-live-windowsserver-assisted method. In macOS14 Sonoma first developer preview, AppKit seems to be rearchitected and window management is all new. All window modifications now seem to be synchronised with display (v-sync) and thus slower. That's fine but if we have two windows moved at the same time (we have a transparent child/parent window which is moved together with window), it's two times slower. That's very slow. NSDisableScreenUpdates or CATransaction doesn't seem to have any effect like they did before. Any ideas?
Posted Last updated
.
Post not yet marked as solved
3 Replies
909 Views
There was a good 2021 WWDC presentation on using ProMotion on iOS, and using Adaptive Sync (ProMotion) on macOS. But while the macOS presentation showed how to detect ProMotion (fullscreen + min/maxInterval mismatch). The iOS side doesn't have this same mechanism. The talk mentions Metal sample code for the talk, but I don't see ProMotion mentioned anywhere in the Metal samples when I do search. https://developer.apple.com/videos/play/wwdc2021/10147/
Posted
by Alecazam.
Last updated
.
Post marked as solved
3 Replies
1.5k Views
I have a view that displays a chart based on an array. Each element in the array is all of the attributes associated with a core data entity. The data is properly displayed. I would like to animate the rendering of the charts data but cannot seem to figure out how to do it. If someone could point me in the right direction it would be appreciated. Below is the code. struct ClosingValuesChart: View { @State private var selectedDate: Date? = nil @State private var selectedClose: Float? = nil @State private var xAxisLabels: [Date] = [] var closingValues: [TradingDayClose] = [] var heading: String = "" init(fundName: String, numYears: Int, closingValues: [TradingDayClose]) { self.heading = fundName + String(" - \(numYears) Year") self.closingValues = closingValues } var body: some View { GroupBox (heading) { let xMin = closingValues.first?.timeStamp let xMax = closingValues.last?.timeStamp let yMin = closingValues.map { $0.close }.min()! let yMax = closingValues.map { $0.close }.max()! let xAxisLabels: [Date] = GetXAxisLabels(xMin: xMin!, xMax: xMax!) var yAxisLabels: [Float] { stride(from: yMin, to: yMax + ((yMax - yMin)/7), by: (yMax - yMin) / 7).map { $0 } } Chart { ForEach(closingValues) { value in LineMark( x: .value("Time", value.timeStamp!), y: .value("Closing Value", value.close) ) .foregroundStyle(Color.blue) .lineStyle(StrokeStyle(lineWidth: 1.25)) } } .chartXScale(domain: xMin!...xMax!) .chartXAxisLabel(position: .bottom, alignment: .center, spacing: 25) { Text("Date") .textFormatting(fontSize: 14) } .chartXAxis { AxisMarks(position: .bottom, values: xAxisLabels) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) AxisValueLabel(anchor: .top) { if value.as(Date.self) != nil { Text("") } } } } .chartYScale(domain: yMin...yMax) .chartYAxisLabel(position: .leading, alignment: .center, spacing: 25) { Text("Closing Value") .font(Font.custom("Arial", size: 14)) .foregroundColor(.black) } .chartYAxis { AxisMarks(position: .leading, values: yAxisLabels) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) AxisValueLabel() { if let labelValue = value.as(Double.self) { Text(String(format: "$ %.2f", labelValue)) .textFormatting(fontSize: 12) } } } } .chartOverlay { proxy in GeometryReader { geometry in ChartOverlayRectangle(selectedDate: $selectedDate, selectedClose: $selectedClose, proxy: proxy, geometry: geometry, xMin: xMin!, xMax: xMax!, closingValues: closingValues) } } .overlay { XAxisDates(dateLabels: xAxisLabels) } .overlay { DateAndClosingValue(selectedDate: selectedDate ?? Date(), selectedClose: selectedClose ?? 0.0) } } .groupBoxStyle(ChartGroupBoxStyle()) } }
Posted
by ChrisMH.
Last updated
.
Post not yet marked as solved
2 Replies
1.7k Views
Hi, I'm aiming to render frames as close as possible to the presentation time - it's for a smartphone-based VR headset (Google Cardboard style) where ideally there is a "late warp" just before presenting a new frame that applies both lens distortion and also orientation correction to reduce the error in the predicted head pose by leveraging the very latest motion sensor data. So leaving it as late as possible gives better pose predictions. This late warp is a pretty simple pass - just a textured mesh, so it's typically <2ms of GPU time. Thanks to the Developer Labs it's been suggested I could use a compute shader for the warp so it can share GPU resources with any ongoing rendering work too (as Metal doesn't have a public per-queue priority to allow for pre-emption of other rendering work, which is the way this is generally handled on Android). What I'm trying to figure out now is how best to schedule the rendering. With CAMetalLayer maximumDrawableCount set to 2, you're pretty much guaranteed that the frame will be displayed on the next vsync if rendering completes quickly enough. However sometimes the system seems to hold onto the drawables a bit longer than expected which blocks getNextDrawable. With maximumDrawableCount of 3, it seems easy enough to maintain 60FPS but looking in instruments the CPU to display latency varies - there are times where its around 50ms (ie already 2 frames in the queue to be presented first, waitForNextDrawable blocks), some periods where it's 30 ms (generally 1 other frame queued) and sometimes where it drops down to the ideal 16ms or less. Is there any way to call present that will just drop any other queued frames in the layer? I've tried presentDrawable:drawable atTime:0 and afterMinimumDuration:0 but to no avail. It seems like with CAMetalLayer I'll just have to addPresentedHandler blocks to keep track of how many are queued in the display so I can ensure the queue is generally empty before presenting the next frame. A related question is the deadline for completing the rendering. The CAMetalLayer is in the compositing fast path, but it seems rendering needs to still complete (ie all the GPU workload finished) around 5ms before the next vsync for it to be displayed on the next vsync. I suspect there's a deadline for the frame just in case it needs to be composited but any hints / ideas for handling that would be appreciated. It seems to be slightly device-specific; somewhat unexpectedly, the iPod touch 7 latches frames that finish much closer to the vsync time than the iPhone 12 Pro. I've also just come across AVSampleBufferDisplayLayer that I'm taking a look at now. It seems to offer better control of the queue, and still enables the compositing fast path, but I can't actually see any feedback like addPresentedHandler to be able to judge what the deadline is to have a frame shown in the next vsync.
Posted Last updated
.
Post not yet marked as solved
0 Replies
769 Views
I've been playing around with the awesome UIViewPropertyAnimator, but are observing something during scrubbing I don't quite understand. Linearly scrubbing a UIViewPropertyAnimator configured with "fast" timing parameters and/or low animation duration, causes the animated properties to snap between (larger) values at the start of scrubbing. This can be made visible with a simple bottom sheet example (recorded on iPhone 14 Pro with iOS 16.4.1): Small/"fast" timing parameters: Large/"slow" timing parameters: The UIViewPropertyAnimator is instantiated as follows (the issue also observed with other initializers): // duration set to 0.25 gives the unwanted snapping at the start of scrubbing: UIViewPropertyAnimator(duration: 0.25, dampingRatio: 1) // duration set to 1.25 gives the expected smooth scrubbing. UIViewPropertyAnimator(duration: 1.25, dampingRatio: 1) Any ideas about what's going on here? I would expect the scrubbing to be smooth independent of what parameters are given? It's especially odd that the snapping only happens at the start of the scrubbing... Also attached the full example code: BottomSheetAnimationViewController.txt
Posted
by Smed1.
Last updated
.