p5.js icon indicating copy to clipboard operation
p5.js copied to clipboard

large webGL canvases draw at unpredictable locations

Open aferriss opened this issue 4 years ago • 2 comments
trafficstars

Most appropriate sub-area of p5.js?

  • [ ] Accessibility (Web Accessibility)
  • [ ] Build tools and processes
  • [ ] Color
  • [ ] Core/Environment/Rendering
  • [ ] Data
  • [ ] DOM
  • [ ] Events
  • [ ] Friendly error system
  • [ ] Image
  • [ ] IO (Input/Output)
  • [ ] Localization
  • [ ] Math
  • [ ] Unit Testing
  • [ ] Typography
  • [ ] Utilities
  • [X] WebGL
  • [ ] Other (specify if possible)

Details about the bug:

I noticed that when trying to draw very large graphics objects to the canvas, it doesn't seem to be drawing in the correct location. I noticed this happening yesterday when using a couple canvases around 5000px, and today again when using canvases > 6000px.

They seem to be drawing down and to the left for some reason. I'm attaching a sketch showing the issue and a screenshot here as well.

https://editor.p5js.org/aferriss/sketches/aMrQqoKF2

Screen Shot 2021-04-03 at 1 46 25 PM
  • p5.js version: 1.3.1
  • Web browser and version: Chrome
  • Operating System: Mac OSX
  • Steps to reproduce this:
  1. Create a large graphics object (>6000px)
  2. Draw some things into that graphics object
  3. Try to draw that object at the origin.

aferriss avatar Apr 03 '21 20:04 aferriss

I can reproduce in Chrome 89.0.4389.114.

It is not happening in Firefox 87 or Safari 14.0.3.

stalgiag avatar Apr 05 '21 16:04 stalgiag

Its two separate bugs - 1: large canvas will not be placed at 0,0- this bug is in the image function. 2: the shape will not be drawn in the correct position on the graphics buffer. I replicate it with other shapes as well. Expected behavior - the shape position will be 0,0 to shape width/height relative to the buffer canvas.

I can confirm that I can replicate the bug even with canvas with the same size (6000) as the buffer. https://editor.p5js.org/DavidWeiss2/sketches/DrcGxko2O

DavidWeiss2 avatar Apr 12 '21 07:04 DavidWeiss2

Update:

When canvas2 is made on main canvas using img function, the function starts breaking after the size of canvas2 is increased beyond 5500 roughly. Also this is only happening in webgl and not p2d canvas.

  • On Chrome canvas2 behaves okay with p2d but not webgl
  • On Firefox canvas2 behaves okay with both p2d and webgl
let canvas2;
function setup() {
  createCanvas(400, 400);
  // canvas2 = createGraphics(400, 400, WEBGL);       // canvas 2 same size as main, no issues
  // canvas2 = createGraphics(5500, 5500, WEBGL);  // till 5500(approx) no unwanted behaviour
  canvas2 = createGraphics(6500, 6500, WEBGL); // position of canvas 2 changed, unwanted
  // canvas2 = createGraphics(6500, 6500); // switch between webgl and p2d on chrome to see the bug

}

function draw() {
  background(0, 0, 255);
  canvas2.background(255, 0, 0);
  
  // behaviour confirmed in both ways
  // image(canvas2, 0, 0, width, height);
  image(canvas2, 0, 0, width/2, height/2);
  
  noLoop();
}

After debugging and reaching the LOC where the new canvas2(buffer) is drawn on the main canvas. this.drawingContext.drawImage(cnv, s * sx, s * sy, s * sWidth, s * sHeight, dx, dy, dWidth, dHeight); the arguments passed are same in both firefox and chrome. image image

AryanKoundal avatar Feb 20 '23 15:02 AryanKoundal

Thanks for helping debug this @AryanKoundal! If the issue is happening in the drawingContext.drawImage call, the bug is likely not something we can directly control. I tried looking into the Chromium and Firefox source code to see what the discrepancy might be, and it looks like it might be due to the precision of the numbers used in drawImage.

Here's the implementation of drawImage in Firefox. Note that the numbers are doubles: image

In the implementation in Chromium, it uses SkScalar as the datatype (the implementation for drawing from a source to a destination rectangle uses SkRect, which just has four SkScalars.) image

It seems that this is just a float:

image:

I imagine this would become a problem when doing calculations to fit one rectangle into another. Maybe we can check if we still have issues if we only drawImage(image, dx, dy) without the other parameters? If so, maybe we can add a check to see if our more complicated function call can be simplified to just dx and dy, and in that case, use that. For cases where we do need the long version (or if the short version still has issues), this might have to be something we decide we can't fix.

davepagurek avatar Mar 04 '23 20:03 davepagurek