Comments (5)
Minimal repro case, based on extracting the offending line segment from the assert failure:
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M-0.36201912 1.7544264e-13L1354.9857 1.7544264e-13 100 100" fill="#ff0"/>
</svg>
This renders with artifact on GPU, which is an additional indication that the assert is detecting a real problem.
from vello.
After a little more digging, I have a clearer picture what's going on. It's a horizontal line which is not exactly grid aligned (but obviously very close). If it were aligned, then the line would be discarded by the numerical robustness logic. On the CPU, a
is being computed as 1, which is correct. However, b
should be 1-epsilon, and it's being rounded up to 1. When computing floor(a*i+b) it should round down to i, but is instead i + 1. That in turn selects a grid square which is not part of the rasterization of the line, which triggers the assertion failure and other mischief.
The fix is not yet clear, though I've got the general outline. Obviously 0 <= b < 1 should be enforced, and if that's satisfied, then floor(a*i+b) should be 0 for the i=0 case. But I'm still worried about i=n-1 in particular.
Another thing that can go wrong is that a should be equal to 1 in the horizontal line case, but it can be <1 because it's calculated as dx * (dx + dy).recip(), which can have roundoff errors. As noted in the review for #374, if that's calculated on CPU using division, you get the right answer, but the guarantees of WGSL are weaker than IEEE floating point.
Obviously a patch to fix this specific error is to special case horizontal lines, but that's not satisfying, as it seems clear it wouldn't cover all failures. I think a good next step would be to carefully define what values for a, b are correct, then put in logic to enforce that, possibly some combination of clamping and verifying that floor(a * (n - 1) + b) is the right value. I'll think on it some more.
from vello.
Ok, I've slept on it, and I believe the following will work. Compute b by taking the min with 0.99999994, which will guarantee it's strictly less than 1. Then compute floor(a * (n - 1) + b) and check whether it's equal to max(1, ceil(max(x0, x1)) - floor(min(x0, x1))) - 1. Note: that's the same value as for computing the count, and it's equal to the width in grid cells of the rasterized line minus one. If not equal, bump a by some epsilon (I believe 1e-9 is fine) with the sign needed to make that equal.
There's more work that can be done to validate this, but I believe that would result in fully robust rendering, and also reduces the pressure on the division operation to compute a. Note that this would also apply to multisampled rendering in fine (see the reviews for the msaa PR, linked above).
from vello.
1e-9 is not fine, we're in f32 world, that's less than 1 ulp. I think 1e-7 is adequate, but the argument is subtle.
from vello.
I believe this can be considered fixed as per the linked PR.
from vello.
Related Issues (20)
- Long startup time under DX12 HOT 2
- [Question] was rust-gpu evaluated? HOT 2
- rustfmt settings (linebender-wide?) HOT 2
- Switch from `dialoguer` to `inquire` HOT 5
- Introduce a changelog HOT 1
- Appending an `Encoding` to a `Scene` HOT 5
- Simple example doesn't work on web. HOT 2
- Trouble drawing emojis HOT 8
- Improving bump estimation accuracy and performance
- API Issue for `Renderer`
- Full system hang on Apple M1 8GB HOT 9
- Rendering to a surface and transparency HOT 2
- Minor issue: example 'simple' - when compiled standalone - the render context needs to be unwrapped HOT 2
- Winit example slow on wsl HOT 4
- Lots of wgpu error messages HOT 5
- `vello_shaders` causes recompilation HOT 1
- How to figure out the correspondence of window size and image size HOT 4
- wgpu: Use `write_buffer_with` rather than `write_buffer` HOT 2
- Update ARCHITECTURE.md HOT 2
- Issue with flattening of a stroked cubic around a near-cusp
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vello.