Skip to content

rounded rectangle performance in P2D / P3D is extremely poor when stroke is used #1566

Description

@clankill3r
Image

MacBook Air M3
Processing 4.5.6 (but also older versions apply)

This runs at around 8.5 fps.

void setup() {
  size(800, 800, P2D);
  frameRate(999);
}

void draw() {
  background(0);

  int cols = 16;
  int rows = 16;
  float margin = 50;
  float gap = 10;

  float rectW = (width - margin * 2 - gap * (cols - 1)) / cols;
  float rectH = (height - margin * 2 - gap * (rows - 1)) / rows;

  fill(255, 220, 0);
  stroke(255);
  strokeWeight(2);
  
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      float px = margin + x * (rectW + gap);
      float py = margin + y * (rectH + gap);

      rect(px, py, rectW, rectH, 10);
    }
  }

  println(frameRate);
}

Activity

  1. hx2A commented on Aug 24, 2026

    @hx2A
    Contributor

    Hi @clankill3r ! Thanks for opening this issue.

    It is intriguing to me that the performance of your Sketch is so different when stroke is used. I wouldn't have expected it to be so significant.

    I thought about it for a while and realized your Sketch would be faster if it could create one rounded rectangle with stoke as a PShape and then draw that PShape object to the screen 256 times. With this approach it would not have to duplicate the curved edge calculations so many times. That's what is causing the performance problem.

    Here is a workaround, using createShape():

    void setup() {
      size(800, 800, P2D);
      frameRate(999);
    }
    
    void draw() {
      background(0);
    
      int cols = 16;
      int rows = 16;
      float margin = 50;
      float gap = 10;
    
      float rectW = (width - margin * 2 - gap * (cols - 1)) / cols;
      float rectH = (height - margin * 2 - gap * (rows - 1)) / rows;
    
      fill(255, 220, 0);
      stroke(255);
      strokeWeight(2);
      
      PShape rect = createShape(RECT, 0.0, 0.0, rectW, rectH, 10);
      
      for (int y = 0; y < rows; y++) {
        for (int x = 0; x < cols; x++) {
          float px = margin + x * (rectW + gap);
          float py = margin + y * (rectH + gap);
    
          shape(rect, px, py);
        }
      }
    
      println(frameRate);
    }

    The documentation for that method is here:

    https://processing.org/reference/createShape_.html

    I often forget that createShape() can also be used to create primitives shapes. It is a useful feature.

  2. clankill3r commented on Aug 24, 2026

    @clankill3r
    Author

    @hx2A Hi, I'm very well aware of that. However this is just a minimal example to demonstrate the issue.
    Another way is to draw bigger rectangles with the stroke color but no stroke first and then draw the fill one on top.
    This is faster.

    Hover using that or solving it with a PShape is a workaround. Computers are so fast nowadays, so this rendering at barely 9fps means the implementation is suboptimal.

  3. catilac commented on Sep 17, 2026

    @catilac
    Collaborator

    Thanks for pointing this out @clankill3r and for the optimization suggestion @hx2A. We are updating much of our rendering engine in what will be Processing 5.0. For 4.x this will be a lower priority item as we continue to transition towards only patch releases for that major version.

    I will be adding documentation for you to catch up on what is going on with 5.0 and our plans. However, you can join our discord to learn more, and you can also check out the core of the rendering work here: https://github.com/processing/libprocessing.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions