Re: lockFocusIfCanDraw behavior in layer-backed mode
Re: lockFocusIfCanDraw behavior in layer-backed mode
- Subject: Re: lockFocusIfCanDraw behavior in layer-backed mode
- From: Tor Arne Vestbø <email@hidden>
- Date: Sun, 23 Dec 2018 14:41:42 +0000
- Thread-topic: lockFocusIfCanDraw behavior in layer-backed mode
Thank you Matt for a very detailed and thorough reply! This is very useful and
clarifying information.
> On 17 Dec 2018, at 20:39, Matt Jacobson <email@hidden> wrote:
>
> Even if it were, it’s still unsafe to ignore the rect passed to -drawRect:.
> That’s because the system might require you to redraw a larger area than what
> your code thinks needs to be redrawn.
Speaking of this, getRectsBeingDrawn: doesn’t seem to work outside of
drawRect:, e.g. in displayLayer:. Is there any way to get at CA/AppKit’s view
of what needs redrawn another way? Without this information we’re forced to do
full updates on every repaint, even when originating from say
setNeedsDisplayInRect:CGRectMake(50, 50, 10, 10).
>> (I know this is a bad ida, but) is there a way to achieve the same
>> synchronous flush with layer-backing?
>
> No.
>
> The imperative view drawing model you’re describing has long been
> discouraged. Among others problems, imperative drawing disrupts the drawing
> of overlapping views (both siblings and superview–subview pairs), is
> incompatible with layer-backed views, and prevents system drawing
> optimizations.
Right. We are aware of the situation. Unfortunately Qt’s Widget module assumes
an imperative drawing model.
During AppKit driven updates the flow goes something like this:
- [QNSView drawRect:] or [QNSView displayLayer:] (depending on whether
layer-backing is enabled or not)
- QCocoaWindow::handleExposeEvent(dirtyRegion)
- QWidgetBackingStore::beginPaint()
- QWidgetBackingStore::endPaint()
- QWidgetBackingStore::flush()
- QCocoaBackingStore::flush()
- a) non-layer-backed
- [view lockFocusIfCanDraw] (if
there’s no focusView)
- [backingStoreImage
drawInRect:]
- [view unlockFocus] and
[view.window flushWindow] (if there was no focusView)
- b) layer-backed
- view.layer.contents =
CGImageFrom(backingStoreImage)
But when QtWidget drives an update, say after clicking a button, we end up with:
- Qt’s CFRunLoopSource for posted events
- QWidgetWindow::event(QEvent::UpdateRequest):
- QWidgetBackingStore::beginPaint()
- QWidgetBackingStore::endPaint()
- QWidgetBackingStore::flush()
- QCocoaBackingStore::flush()
- a) non-layer-backed
- [view lockFocusIfCanDraw] (if
there’s no focusView)
- [backingStoreImage
drawInRect:]
- [view unlockFocus] and
[view.window flushWindow] (if there was no focusView)
- b) layer-backed
- view.layer.contents =
CGImageFrom(backingStoreImage)
https://github.com/qt/qtbase/blob/5.12/src/plugins/platforms/cocoa/qcocoabackingstore.mm#L81
A similar situation happens when an animation is driven by a CVDisplayLink,
where the display-link callback coming in on the secondary thread is delivered
to the main thread via dispatch_source event handler, so we’re again drawing &
flushing outside of the display cycle.
https://github.com/qt/qtbase/blob/5.12/src/plugins/platforms/cocoa/qcocoascreen.mm#L270
If we can’t (shouldn’t) do any imperative drawing, should a CVDisplayLink
callback always just call setNeedsDisplay and let the callback be coalesced
into the main runloop's display cycle? Even for OpenGL or Metal, where you can
present a frame imperatively?
> • using -[NSImage initWithSize:flipped:drawingHandler] to capture
> drawing code into a block; by drawing that image in -drawRect:, you’ll defer
> execution of the drawing code until then
This one looks interesting!
>
> I hope this helps!
Very much so, thanks again!! 😊
Cheers,
Tor Arne
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden