JDK-8148549 : Region is not rendered correctly when node cache is enabled
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2016-01-23
  • Updated: 2020-01-31
  • Resolved: 2017-02-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u152Fixed 9Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)

Bug can be reproduced with all JavaFX versions since 2.0 and is still present in the current release.

ADDITIONAL OS VERSION INFORMATION :
1.) OS X 10.11.3: 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64

2.) Windows 10 x64

3.) Linux (Ubuntu x64)

EXTRA RELEVANT SYSTEM CONFIGURATION :
Bug can be reproduced with NVidia, ATI and Intel graphics cards.

A DESCRIPTION OF THE PROBLEM :
Enabling caching can cause serious rendering bugs, even in simple demo programs. Use a region, enable caching and resize the region and disable caching afterwards causes these rendering bugs. Unfortunately, the region isn't correctly rendered and dirty areas with ugly artifacts appear.

Enabling showDirtyOpts indicates that dirty-rectangles are computed correctly. But the actual rendering is broken. Disabling dirtyOpts does not solve the problem.

Example video that shows the rendering bug: https://www.dropbox.com/s/1qwnz1sargs93l1/Cache%20Bug%2001.m4v?dl=0

Sample code: https://gist.github.com/miho/ab1fff7f483c7f7409b4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute sample program shown below and enable/disable caching (e.g. press toggle-cache button once per second). 

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Correct rendering.
ACTUAL -
See https://www.dropbox.com/s/1qwnz1sargs93l1/Cache%20Bug%2001.m4v?dl=0

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// https://gist.github.com/miho/ab1fff7f483c7f7409b4

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 * This JavaFX applications demonstrates strange rendering artifacts.
 *
 * Enabling a regions {@code cache} property and resizing the region causes
 * serious rendering bugs. Te reproduce the behavior just press the toggle
 * button (e.g. once a second).
 *
 * @author Michael Hoffer <info@michaelhoffer.de>
 */
public class CacheBug01 extends Application {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        // we print the java version to be sure that we use the right jdk
        System.out.println(
                "java-version: "
                + System.getProperty("java.version")
        );

        // create and initialize region
        // this region isn't updated and causes rendering artifacts (see below)
        Region r = new Region();
        r.setCacheHint(CacheHint.SCALE);
        r.setPrefWidth(30);
        r.setPrefHeight(30);
        r.setStyle(""
                + "-fx-border-color: red;"
                + "-fx-background-color: rgba(0,0,0,0.4);"
                + "-fx-border-color: red;");

        // resize animation (prefWidth/prefHeight properties)
        Timeline l = new Timeline(
                new KeyFrame(Duration.ZERO,
                        new KeyValue(r.prefWidthProperty(), 30),
                        new KeyValue(r.prefHeightProperty(), 30)
                ),
                new KeyFrame(Duration.seconds(2),
                        new KeyValue(r.prefWidthProperty(), 400),
                        new KeyValue(r.prefHeightProperty(), 400)
                )
        );
        l.setAutoReverse(true);
        l.setCycleCount(Timeline.INDEFINITE);
        l.play();

        // region container
        Pane pane = new Pane(r);
        pane.setPrefSize(400, 400);

        // cache toggle btn
        String cacheBtnString = "Toggle Cache: r.isCache() -> ";
        ToggleButton cacheBtn = new ToggleButton(cacheBtnString + r.isCache());
        cacheBtn.setPrefWidth(300);
        r.cacheProperty().bind(cacheBtn.selectedProperty());
        r.cacheProperty().addListener((ov) -> {
            cacheBtn.setText(cacheBtnString + r.isCache());
        });

        // root box
        VBox root = new VBox(cacheBtn, pane);
        root.setAlignment(Pos.CENTER);

        // usual scene/stage setup
        Scene scene = new Scene(root, 400, 450);
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Cache Bug 01");
        primaryStage.show();
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Since caching is necessary during animation, no simple workaround exists. 


Comments
Approved to backport to 8u-dev for 8u152. +1 for pushing to 8u-dev.
17-02-2017

http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/8009b3cdf575
09-02-2017

+1
09-02-2017

+1 for pushing to 9-dev
09-02-2017

The patch applies cleanly to 8u-dev (with sourcefile path name changes) and fixes the problem there as well. gradle test also completes successfully with the fix for both 9 and 8u-dev
08-02-2017

http://cr.openjdk.java.net/~flar/JDK-8148549/webrev.00/
08-02-2017

When the size of a region changes and NGRegion.setSize() is called, it doesn't indicate that the visuals changed (which invalidates the cached image). setShape() does this so I copied a line from setShape to setSize() and this works fine now...
08-02-2017

Retargeted to tbd_major as not a regression in 8u/9 and introduced in 8 GA or earlier. However might be fixed in 9 in positive case on time resources
11-07-2016

I can reproduce this bug on both Mac and Windows. The rendering is incorrect when the size of the region is changed (via animating the preferred width and height), it appears to render the cached content at the size it was cached.
26-04-2016