Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8128785

Texture to image conversion is broken with ES2 pipeline

    XMLWordPrintable

Details

    Description

      The testcase below is minimized Webnode code that converts RTTexture to com.sun.prism.Image. It dumps the texture into a ByteBuffer, then creates an Image from that buffer. On Windows this works fine, on Mac red and green channels get interchanged, i.e. cyan is painted instead of magenta. So this issue seems to be pipeline specific, though I didn't try ES2 on Windows.

      The essential code is in the renderWithPattern() method. Both the texture and the image are reported to have the same format, BYTE_BGRA_PRE. Changing byte order does not make any difference.

      import com.sun.javafx.geom.BaseBounds;
      import com.sun.javafx.geom.transform.BaseTransform;
      import com.sun.javafx.jmx.MXNodeAlgorithm;
      import com.sun.javafx.jmx.MXNodeAlgorithmContext;
      import com.sun.javafx.sg.PGNode;
      import com.sun.javafx.sg.prism.NGGroup;
      import com.sun.prism.Graphics;
      import com.sun.prism.GraphicsPipeline;
      import com.sun.prism.Image;
      import com.sun.prism.RTTexture;
      import com.sun.prism.ResourceFactory;
      import com.sun.prism.paint.Color;
      import com.sun.prism.paint.ImagePattern;
      import java.nio.ByteBuffer;
      import java.nio.ByteOrder;
      import javafx.application.Application;
      import javafx.scene.Group;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.stage.Stage;


      public class CustomNodeApp extends Application {
          final int WIDTH = 400;
          final int HEIGHT = 300;
          final Color COLOR = new Color(1f, 0f, 1f, 1f); // magenta
              
          class CustomNode extends Node {
          
              @Override public Object impl_processMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
                  return null;
              }

              @Override protected PGNode impl_createPGNode() {
                  return new NGCustomNode();
              }

              @Override public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
                  bounds.deriveWithNewBounds(0, 0, 0, WIDTH, HEIGHT, 0);
                  tx.transform(bounds, bounds);
                  return bounds;
              }

              @Override protected boolean impl_computeContains(double localX, double localY) {
                  return true;
              }
          }
          
          class NGCustomNode extends NGGroup {

              @Override public boolean hasOverlappingContents() {
                  return false;
              }
              
              @Override protected void renderContent(Graphics g) {
      // renderDirectly(g); // works fine
                  renderWithPattern(g); // renders cyan instead of magenta
              }

              void renderDirectly(Graphics g) {
                  g.clear(COLOR);
              }

              void renderWithPattern(Graphics g) {
                  // render scene to a texture
                  ResourceFactory f = GraphicsPipeline.getDefaultResourceFactory();
                  RTTexture txt = f.createRTTexture(1, HEIGHT);
                  txt.createGraphics().clear(COLOR);
                  System.out.println("texture format: " + txt.getPixelFormat());
                  
                  // convert texture to an image
                  ByteBuffer buf = ByteBuffer.allocate(HEIGHT * 4);
                  buf.order(ByteOrder.nativeOrder()); // makes no difference
                  buf.rewind();
                  txt.readPixels(buf);
                  Image img = Image.fromByteBgraPreData(buf, 1, HEIGHT);
                  System.out.println("image format: " + img.getPixelFormat());

                  // create a pattern from the image and paint it
                  buf.rewind();
                  ImagePattern pattern = new ImagePattern(img, 0, 0, 1, HEIGHT, false);
                  g.setPaint(pattern);
                  g.fillRect(0, 0, WIDTH, HEIGHT);
              }
          }
          
          @Override public void start(Stage stage) {
              stage.setScene(new Scene(new Group(new CustomNode())));
              stage.sizeToScene();
              stage.show();
          }
          
          public static void main(String[] args) {
              launch();
          }
      }

      Attachments

        Issue Links

          Activity

            People

              ckyang Chien Yang (Inactive)
              peterz Peter Zhelezniakov
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported: