-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Swing interop: off-screen rendering on graphics #601
Conversation
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Outdated
Show resolved
Hide resolved
|
||
abstract val renderApi: GraphicsApi | ||
|
||
abstract val clipComponents: MutableList<ClipRectangle> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same here. I delegate some parts of SkiaLayer here, so it can be used in ComposePanel, may beyou can propose better solution...
* See also backendLayer for standalone compose [androidx.compose.ui.awt.ComposeWindowLayer.ComposeWindowSkiaLayer] | ||
*/ | ||
@OptIn(ExperimentalSkikoApi::class) | ||
private inner class ComposeSwingSkiaLayer : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code of these layers are kinda the same. I thought about having Wrapper JPanel and override these methods there and add SkiaLayer to it, but I think that something may go wrong in this case.
Do we really need Is this not what we want:
|
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Show resolved
Hide resolved
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeWindowLayer.kt
Outdated
Show resolved
Hide resolved
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Show resolved
Hide resolved
@m-sasha Regarding Later, yes, we will remove it and have only SkiaSwingLayer, and some logic will be simplified |
The names are too much here. Both too long and not very informative. I'm not sure I have better suggestions off the top of my head, but I'd really love some.
🤯 |
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposePanel.desktop.kt
Outdated
Show resolved
Hide resolved
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Outdated
Show resolved
Hide resolved
} | ||
|
||
protected fun resetSceneDensity() { | ||
if (scene.density != component.density) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure you can trust Density.equals
to work correctly. It's an interface with many different implementations.
Perhaps we shouldn't be using the Compose Density
at this level at all, but a single scale: Float
value. The fontScale
seems to always be 1f
here anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I didn't get the second point, can you elaborate it? With the first one I agree, it seems we need to make density.density
check here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the 2nd point:
GraphicsConfiguration.density
is currently a Density
object with fontScale=1f
. Maybe we should replace it with a GraphicsConfirguration.scale: Float
property, and only create a Density
from it where it's actually exposed to the user (in LocalDensity
and such). Internally, only deal with a scale: Float
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an interesting point. @igordmn WDYT?
I'd also keep it out of scope, but I would like to fix it in a separate PR after merging this one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is true that Density can be just some abstract object (look at its descendants).
But for simplicity, I wouldn't change it. The correct equals
, or equals
by reference - both work here. It is the similar to the check when we change LocalDensity
.
is currently a Density object with fontScale=1f
We have an issue for supporting fontScale
(macOs doesn't have it, Windows/Linux have it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand how equals
can work correctly here. If there are two implementations of Density
that don't know about each other, comparing them for equality will likely return false
. For example:
private data class MyDensity(
override val density: Float,
override val fontScale: Float
) : Density
fun main(){
val density1 = Density(1.0f, 1.0f)
val density2 = MyDensity(1.0f, 1.0f)
println(density1 == density2)
}
prints false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not about comparing 2 implementations (they indeed aren't equals), it is about GraphicsConfiguration.density
returning the same instance if it wouln't implement equals
:
val d = MyDensity(1.0f, 1.0f)
val GraphicsConfiguration.density get() = d
fun foo() {
if (scene.density != graphicsConfiguration.density) {
// only performs once
println("update density")
}
}
LocalDensity
, ComposeScene.density
has an impilicit performance contract that it needs to be the equal instance to avoid recompositions. Either by implemented equals
, or just the same instance.
GraphicsConfiguration.density
complies this contract using equals
, but returning the same instance will work as well.
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Outdated
Show resolved
Hide resolved
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Outdated
Show resolved
Hide resolved
_initContent?.invoke() | ||
_initContent = null | ||
} | ||
} | ||
|
||
private fun setCurrentKeyboardModifiers(modifiers: PointerKeyboardModifiers) { | ||
platform.windowInfo.keyboardModifiers = modifiers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a problem here. platform.windowInfo.keyboardModifiers
needs to be set from a listener on events on the window, not just the component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a really good point! But let's fix it separately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, it should listen the window.
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeSwingLayer.desktop.kt
Outdated
Show resolved
Hide resolved
…hics for smooth Swing interop
…omposeLayer.desktop.kt Co-authored-by: Ivan Matkov <[email protected]>
…nce width and height shouldn't be negative
64e71a8
to
4f1c1e3
Compare
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/ComposeLayer.desktop.kt
Outdated
Show resolved
Hide resolved
private fun createComposeLayer(): ComposeLayer { | ||
val renderOnGraphics = System.getProperty("compose.swing.render.on.graphics").toBoolean() | ||
val layer: ComposeLayer = if (renderOnGraphics) { | ||
ComposeSwingLayer(skiaLayerAnalytics) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found 2 bugs on Windows (i.e. software rendering) when we run ./gradlew runSwing
:
- When press "SOUTH/REMOVE COMPOSE", Compose panel isn't removed (but shouldn't)
- When we press New window, we have a 2-3 second lag
They can be fixed separately I believe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the first one -- issue is inside the example, fixed it, please check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't SkiaLayer itself call it?
panel.revalidate()
panel.repaint()
From my non-Swing perspective, I expect panel.remove
to be the only function needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't be called, in most of the cases, when you remove a component from a hierarchy, you need to call revalidate + repaint. I haven't found a documentation part regarding this, but this is from my experience.
_initContent?.invoke() | ||
_initContent = null | ||
} | ||
} | ||
|
||
private fun setCurrentKeyboardModifiers(modifiers: PointerKeyboardModifiers) { | ||
platform.windowInfo.keyboardModifiers = modifiers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, it should listen the window.
} | ||
|
||
protected fun resetSceneDensity() { | ||
if (scene.density != component.density) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is true that Density can be just some abstract object (look at its descendants).
But for simplicity, I wouldn't change it. The correct equals
, or equals
by reference - both work here. It is the similar to the check when we change LocalDensity
.
is currently a Density object with fontScale=1f
We have an issue for supporting fontScale
(macOs doesn't have it, Windows/Linux have it)
Proposed Changes
This PR is related to JetBrains/skiko#720
Testing
Test: Since skiko PR is not merged yet, it is needed to build skiko part locally and then test it on swingExample from desktop examples passing "-Dcompose.swing.render.on.graphics=true"
Issues Fixed
It will partially fix: JetBrains/compose-multiplatform#2925
And other interop issues related to rendering