gluonhq / substrate

Create native Java(FX) apps for desktop, mobile and embedded
GNU General Public License v2.0
396 stars 51 forks source link

Ubuntu native image error: CPU/Java peer not found for: Blend_ADD due to error: com.sun.scenario.effect.impl.sw.java.JSWBlend_ADDPeer #1297

Open credmond opened 1 day ago

credmond commented 1 day ago

Getting this error when running a native image on Linux.

Assume it has to be related to using one of these classes:

import javafx.animation.FadeTransition;
import javafx.scene.effect.Glow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

Note, I have <enableSWRendering>true</enableSWRendering> set for other reasons (issues with Linux GPU combos) -- it could be related, but I've had that setting for 2 years and the app is otherwise okay -- used Images and Reflections in other places before.

The native image outputs these errors over and over (works ok on Windows and Mac and other Linux's):

`Error: CPU/Java peer not found for: Blend_ADD due to error: com.sun.scenario.effect.impl.sw.java.JSWBlend_ADDPeer
java.lang.RuntimeException: Could not create peer  Blend_ADD for renderer com.sun.scenario.effect.impl.prism.sw.PSWRenderer@57ab4862
        at com.sun.scenario.effect.impl.Renderer.getPeerInstance(Renderer.java:262)
        at com.sun.scenario.effect.CoreEffect.getPeer(CoreEffect.java:66)
        at com.sun.scenario.effect.CoreEffect.getPeer(CoreEffect.java:92)
        at com.sun.scenario.effect.CoreEffect.filterImageDatas(CoreEffect.java:106)
        at com.sun.scenario.effect.Blend.filterImageDatas(Blend.java:37)
        at com.sun.scenario.effect.FilterEffect.filter(FilterEffect.java:195)
        at com.sun.scenario.effect.DelegateEffect.filter(DelegateEffect.java:70)
        at com.sun.scenario.effect.impl.prism.PrEffectHelper.render(PrEffectHelper.java:166)
        at com.sun.javafx.sg.prism.EffectFilter.render(EffectFilter.java:61)
        at com.sun.javafx.sg.prism.NGNode.renderEffect(NGNode.java:2386)
        at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2071)
        at com.sun.javafx.sg.prism.NGImageView.doRender(NGImageView.java:103)
        at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1966)
        at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
        at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
        at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2074)
        at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1966)
        at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
        at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
        at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2074)
        at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1966)
        at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
        at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
        at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2074)
        at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1966)
        at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
        at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
        at com.sun.javafx.sg.prism.NGNode.renderOpacity(NGNode.java:2359)
        at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2062)
        at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1966)
        at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:480)
        at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:329)
        at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:143)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
        at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:126)
        at java.lang.Thread.run(Thread.java:833)
        at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
        at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)`

Environment: Ubuntu 22.04.3 LTS (WSL), substrate 1.0.23. Jfx: 21.0.4...

Any ideas?

johanvos commented 1 day ago

Since this is at runtime, is it possible that on the other systems HW rendering is used, and on this one the fallback to SW is done? In that case, there are probably classes missing in the reflection-config that are only needed with SW rendering (and even then in some some specific styles/shaders only). A solution would then be to manually add those missing files to the reflection-config -- either manually or having the agent doing it for you. It's important though to run with prism-sw. Only enabling it is not going to pick it by default (iirc), so you must set it explicitly like e.g. System.setProperty("prism.order", "sw"); Also, add `System.setProperty("prism.verbose", "true") to get log info about whether the HW pipeline or the SW pipeline is selected.

Even in this case, it's not a real good solution, but we have conflicting boundary conditions here:

  1. we want the native image to be as small as possible
  2. we want the image to be executable on as many systems as possible

Adding all sw-specific code in the image will violate the first condition, but ignoring it violates the second condition. A more hybrid model that allows to run dynamic code in case something is not in the image would help here. That is far from trivial, but I keep thinking about this in the openjdk/mobile project.