Skip to content

Allowing per-vertex fill / stroke changes significantly decreases performance #2022

Closed
@wxs

Description

@wxs

Nature of issue?

  • Found a bug
  • Existing feature enhancement
  • New feature request

Most appropriate sub-area of p5.js?

  • Color
  • Core
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL

New feature details:

As part of my investigation of #2011, I found that drawing complex shapes with beginShape() and endShape() can be very slow with the default Renderer2D

This can be significantly improved by batching calls to the fill and stroke methods of the canvas. One reason right now they are not batched is that the renderer partially supports per-vertex colours, and the way this is implemented is by re-setting the fill and stroke for each primitive in the shape. Here is what that looks like for the TRIANGLES shape type:

 if (shapeKind === constants.TRIANGLES) {
      for (i = 0; i + 2 < numVerts; i += 3) {
        v = vertices[i];
        this.drawingContext.beginPath();
        this.drawingContext.moveTo(v[0], v[1]);
        this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]);
        this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]);
        this.drawingContext.lineTo(v[0], v[1]);
        if (this._doFill) {
          this._pInst.fill(vertices[i + 2][5]);
          this.drawingContext.fill();
        }
        if (this._doStroke) {
          this._pInst.stroke(vertices[i + 2][6]);
          this.drawingContext.stroke();
        }
        this.drawingContext.closePath();
      }
    }

Note that it calls drawingContext.fill() for every single triangle separately.

I have an experimental branch on my machine where I batch these calls instead, so that I only call fill and stroke once for the entire set of triangles, and I see order of magnitude performance improvements when drawing shapes that include many triangles.

Solutions

There are two ways to solve this:

A) Stop supporting per-vertex-colours

The simplest and less error-prone is just to stop supporting per-vertex colours. These are not documented in p5.js anyway, and in Processing are not supported by the default renderer.

B) Detect when vertex colours change

The more complex approach is to batch the calls most of the time, but detect when colours have been changed per-vertex and in that case "un-batch" the calls.

--

I prefer the first approach, as if the user wants they can always just use multiple calls to beginShape and endShape, changing the fill and stroke in between. This has the added benefit that the vertex colour behaviour currently is pretty non-intuitive. For instance, if drawing with TRIANGLES only the colour of every third vertex matters and the rest are ignored.

I have the more complex approach partially implemented (just for TRIANGLE_FAN so far). The advantage here is that it's backwards compatible. The disadvantage is that it makes the code more complex and bug prone. It is also perhaps not as intuitive to users that they will see a performance decrease when setting fills and strokes inside a beginShape, this might be more obvious if they had to explicitly endShape and then beginShape again.

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