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

Rendering Slower in OpenGL (P2D/P3D) than default #203

Closed
rich-gg opened this Issue Apr 1, 2016 · 13 comments

Comments

Projects
None yet
2 participants
@rich-gg
Copy link

rich-gg commented Apr 1, 2016

Hello

I keep testing my little app with default, P2D, P3D and OPENGL rendering and it runs better in default than OpenGL.

My machine is a ShieldK1 with Marshmallow
NVIDIA Corporation
System.out: NVIDIA Tegra
OpenGL ES 3.2 NVIDIA 361.00
OpenGL ES GLSL ES 3.20

I rotate, on screen, 180 instances of a Circle Class rendering 1 plain ellipse(),

  • Default renderer : 30 FPS
  • OPENGL / P2D / P3D : 25 FPS

funny thing is that if I give a strokeWeight(10); to my ellipses, the frame rate drops to like 1 FPS
in any OpenGL but stays the same in default renderer

//// this is quite important for me since I think I am totally stuck without a solution, so I would be very much pleased if I could provide help to the good people that took charge of this part of Processing.
I am ready to proceed to all the tests you need

UPDATE: ran the test in Xperia Z1 compact / Lollipop

  • the Frame rate is up 5 FPS on both default and OpenGL rendering, but OpenGL is still slower than default
@codeanticode

This comment has been minimized.

Copy link
Member

codeanticode commented Apr 1, 2016

Does the fps drop happens only with P2D or also with P3D?

@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 1, 2016

it does behave the same, I mean "as bad", in OPENGL, P2D, P3D

@codeanticode

This comment has been minimized.

Copy link
Member

codeanticode commented Apr 5, 2016

Could you post a minimal sketch that shows the FPS drop?

@codeanticode codeanticode self-assigned this Apr 5, 2016

@codeanticode codeanticode added the opengl label Apr 5, 2016

@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 5, 2016

Hi

here is a first piece of code that shows a problem, frame rate is killed by strokeWeight(>1);

int cx, cy;

    @Override
    public void settings() {
        fullScreen(P2D);
    }

    @Override
    public void setup() {

        cx = width/2;
        cy = height/2;

    }

    @Override
    public void draw() {

        background(128,255,0);

        textSize(40);
        text(frameRate, 20,50);

        noFill();
        strokeWeight(10);
        pushMatrix();
        translate(cx, cy);
        ellipse(0, 0, 100,100);
        popMatrix();

    }

running it on processing on my PC, I get the same FPS with or without P2D
on my android (using android studio and my Nvidia Shield K1) I get :

  • default render : 58-59 FPS
  • P2D render : 48-52 FPS
@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 5, 2016

here is the seconde piece of code that shows a problem, frame rate is lower in P2D that Default


    int cx, cy;
    float alph = 0;

    @Override
    public void settings() {
        fullScreen();
    }

    @Override
    public void setup() {

        cx = width/2;
        cy = height/2;

    }

    @Override
    public void draw() {

        background(128, 255, 0);

        textSize(40);
        text(frameRate, 20, 50);

        noFill();
        strokeWeight(1);

        pushMatrix();
        translate(cx, cy);
        rotate(alph);

        for (int i = -9; i < 10; i++) {
            for (int j = -9; j < 10; j++) {
                ellipse(100 * i, 100 * j, 80, 80);
            }
        }

        popMatrix();

        alph += 0.005;

    }

running it on processing on my PC, I get 40 FPS with default renderder and 60 with P2D
on my android (using android studio and my Nvidia Shield K1) I get :

default render : 24 FPS
P2D render : 8 FPS

  • the use of pushMatrix and the rotate() only help to see the frame rate, it doesn't impact FPS
@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 5, 2016

this might be a little off topic for this issue but spot on for my issue:

  • I just tried my same code on my PC + processing, using FX2D
    WOW !!! it works like a rocket !
    Since my app is 2D, wouldn't it make sens for me to find a way to use JavaFX, instead of P2D ?

@codeanticode codeanticode added invalid wontfix and removed invalid labels Apr 5, 2016

@codeanticode

This comment has been minimized.

Copy link
Member

codeanticode commented Apr 5, 2016

JavaFX is not available on Android, so FX2D won't work. Update: it seems that there is a JavaFX port for Android, but I have no idea how this could potentially be used to re-implement the FX2D renderer for the Android mode, and in any case that is well beyond the scope of this issue (and see my comment at the end).

The reason why P2D is particularly slow when rendering stroked shapes is because it tessellates the stroke geometry using a module that it is implemented in pure Java, and not in native code. This same module is used both in Java and Android modes, but the performance impact is more evident on Android. The only short term solutions I can thing of are the following:

  • Use Java2D instead.
  • Use P3D instead. P3D relies on a faster stroke tessellation algorithm, but the resulting strokes have lower quality, and might also show artifacts if they stroke color is semi-transparent.
  • Store your geometry in PShape objects, so the strokes are tessellated just once during setup:
int cx, cy;
float alph = 0;

PShape group;

void settings() {
  fullScreen(P2D);
}

void setup() {
  cx = width/2;
  cy = height/2;
  group = createShape(GROUP);
  for (int i = -9; i < 10; i++) {
    for (int j = -9; j < 10; j++) {
      PShape circle = createShape(ELLIPSE, 100 * i, 100 * j, 80, 80);
      circle.setFill(false);
      circle.setStroke(true);
      circle.setStrokeWeight(5);
      group.addChild(circle);
    }
  }
}

public void draw() {
  background(128, 255, 0);

  textSize(40);
  text(frameRate, 20, 50);

  pushMatrix();
  translate(cx, cy);
  rotate(alph);
  shape(group);
  popMatrix();

  alph += 0.005;
}

I tried the sketch above on a moto E, and the framerate was steady at 60 fps.

The only long term solution for performant stroked shapes in P2D without using PShape, particularly on Android, would be to implement the stroke tessellator in C, compile as a native library, and call it from Processing through JNI. But this is something I don't have time to do at this moment.

Of course, contributors are welcome!

@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 5, 2016

Nooooo !!

I made the mistake to post about the stroke thing BEFORE the plain render thing
my seconde post talks about the FPS loss in plain ellipse render

@codeanticode

This comment has been minimized.

Copy link
Member

codeanticode commented Apr 5, 2016

@rich The reason causing the fps dropdown in both of your examples is the same, the stroke tessellation algorithm. You can either use Java2D (default renderer), P3D (with lower quality strokes), or use retained mode with PShape. For the first example, the PShape version would be:

int cx, cy;

PShape circle;

void settings() {
  fullScreen(P2D);
}

void setup() {
  cx = width/2;
  cy = height/2;
  circle = createShape(ELLIPSE, 0, 0, 100, 100);
  circle.setFill(false);
  circle.setStrokeWeight(10);

}

void draw() {
  background(128, 255, 0);

  textSize(40);
  text(frameRate, 20, 50);

  pushMatrix();
  translate(cx, cy);
  shape(circle);
  popMatrix();
}
@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 8, 2016

@codeanticode
I think I found the culprit: shapeMode(CENTER);

Once commented this line that I had in setup(), the frame just got unleashed

I tried with CORNER and CORNERS too, idem. It take my FPS down to about the same a default renderer, if not worst.

It might be not so hard to work around that, but I thought you'd like to know

cheers , and thank you for the help !

@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 15, 2016

@codeanticode

I got my P2D render to work out ok using the "Store your geometry in PShape objects" methode you suggested, once I removed the shapeMode(CENTER); line.

but I use graphical objects that need to be "alive" a respond, in there geometry, to real time input.
I am wondering if the strokeWeight() methode that kills my framerate in P2D could be remade using GLSL shader.

Any idea ?

cheers

@codeanticode

This comment has been minimized.

Copy link
Member

codeanticode commented Apr 16, 2016

The solution is not easy. As mentioned earlier, one possibility could be to re-implement the stroke tessellation in native code, and use it from the Java code, this should speed up stroke rendering in P2D significantly.

Re-implementing P2D stroke lines in GLSL is a non-trivial problem, unless you use some sort of approximation. Right now the tessellation is very accurate, so you can set line bevel, caps, etc., so I don't know how all of this functionality could be ported to GLSL. However, shader-based lines is a problem that people have been working on for a while, here you have some useful references:

https://mattdesl.svbtle.com/drawing-lines-is-hard
http://stackoverflow.com/a/19212122
https://forum.libcinder.org/topic/smooth-thick-lines-using-geometry-shader
https://hal.inria.fr/hal-00907326/file/paper.pdf

@rich-gg

This comment has been minimized.

Copy link

rich-gg commented Apr 18, 2016

thank you for that insight

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment