-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add linear gradient support to canvas widget #1448
Conversation
…/linear-gradients # Conflicts: # graphics/src/widget/canvas/frame.rs
… but must be sorted before being passed to shader.
…certain circumstances.
So an example of using custom geometry to interpolate color data without a canvas a la |
…ide a Canvas widget, where it was previously only accessible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great! Excellent 🎉
I left some feedback here and there after a quick glance at the code. Let me know what you think!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work taking this over @bungoboingo! I'm very excited to see this working on the opengl side now, too!
... and move `StaticBuffer` to nested `static` module
... so it makes sense when seen from the `iced` crate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work!!! 🥳
I took a final look and made some changes here and there. Specifically, I have
- Implemented a
BufferStack
incanvas::frame
so we can reuse the last buffer if themesh::Style
matches in 20a0577. We could eventually use aHashMap
orBTreeMap
instead, but this simple approach seems to work quite well since it's likely for users to draw similar styled geometry together. Thegame_of_life
went from having 100+ buffers, to simply having 4! - Implemented color conversion to linear RGB before uploading colors to the GPU in 6246584 and 9a02d60. Generally, shader input/output should be in linear RGB. Otherwise, color blending (and any other color operations) will simply not work as expected.
- Introduced a flag to reuse the latest pipeline if possible in
iced_wgpu
in 93e309f. I noticedset_pipeline
has a noticeable overhead, even if the pipeline is the same as the old one (not completely sure of this, it may have been just a fluke!). - Run
cargo fmt
and fixed a bunch ofclippy
lints in b957453 and 7e22e2d, respectively. - Refactored a bunch of imports and exports, renamed some modules, and moved some types around to remove cyclical dependencies in the other commits. I tried to keep the commits self-contained so you can take a look at them!
With these changes, the game_of_life
example seems to run at pretty much the same speed as in master
(maybe even a bit faster!).
Really great stuff here! Thanks again 🎉 Take a look at the latest changes, make sure I didn't break anything, and then I believe we can merge this!
Tested examples & code looks good. Ready 2 merge I think! Great changes (and I will fmt & clean up commits on my next PR.. sorry!) |
No worries! Great work here 🎉 |
GRADIENTS
This PR adds support for linear gradients (radial & conical TBD) as a
Fill
style for canvas widgets.Please note this does NOT add support for gradients for quads (yet), only 2d meshes on a canvas.
Big thanks to @tarkah for letting me yoink his original linear-gradient wgpu PR to get my feet wet in Iced. 🤗
Known issues:
1) When running examples with both a solid & gradient shader with theglow
backend, only one shader type will be drawn until the window is resized.2) Rainbow example is broken, need to rework it 😢<- this was mutually agreed upon to be removed3) Declaring a color stop offset out of order (e.g. "0.3", "0.6", "0.2", then "1.0") causes the gradient to straight up not workUsage
When creating a primitive you can now change the
FillStyle
to be eitherSolid
or aGradient
. This changes the original field fromcolor
tostyle
. E.g.:Before:
After:
Any direction of linear gradient can be created, with
start
andend
points. Color "stops" are added as a percentage along the total length of the gradient, akin to making a linear-gradient with CSS. So a color stop with an offset of "0.5" would mean the color is fully rendered at 50% of the total length of the gradient. A color stop with an offset of "0.0" would mean the color is fully rendered at 0% of the total length, etc.This builder was created by @tarkah (I yoinked it from his PR) and not sure that git will attribute it correctly, so big thanks to him!!
Implementation Details (Feedback appreciated!)
I am still fairly new to graphics programming, WGPU in particular, so any feedback would be appreciated! 🤗
Iced currently has no support for multiple shader types. In this PR I've attempted to modularize adding new pipelines (wgpu)/programs(opengl) so we can add more shader types easier in the future.
My first change is to remove color data from the current Mesh2D attribute data, leaving only position data as a
Vertex2D
. For gradients this attribute is unneeded and was wasting quite a bit of bytes in the attribute buffers, so it has been purged. For solids as well this wasn't really needed as a fill generally does not switch colors per-vertex, but was probably more efficient than adding a uniform write potentially every draw. I've switched all color information to being uniform based. Performance implications of this TBD.Other areas that were changed:
encase
(crates.io). This ensures compile-time safety for alignment & padding requirements for all uniforms in accordance with the WebGPU specification. This crate is recommended by the WGPU team and used in other large projects using WGPU for easier data management (Bevy being the biggest one). It introduces a derivedShaderType
trait which generates metadata to perform checks on. It also comes with its own CPU buffer implementation which will pad data on write, making it very easy to avoid alignment issues.Known areas to be improved
I will be doing some heavy profiling to see bottlenecks, but there are some obvious areas of improvement that I know will increase performance without doing so.
anyways. But still good to do now if there is a uniform that passes the 256 byte threshold in the future.
4) Uniforms can be rearranged in WGPU to pack them more tightly; working on this now in addition to the known issue(s) above.else
case will get executed every time on the GPU unless it performs some compilation-time unrolling, which, to my knowledge after some small amount of research, seems pretty hit or miss.Areas to improve usability
deg(0)
that you can do with CSS gradients to just have a gradient fill the primitive at the right angle. This would be fairly trivial and just involve a wee bit of math. Keywords likeleft
top
etc would also be useful and make this process less awkward.Edit: I have added a way to use relative positioning, but it still has the requirement of a bounds to know what to position relative to. A tad more cumbersome than the CSS implementation where you know the bounds of the object beforehand so don't need to specify it, but otherwise might be more comfortable to use in certain use-cases. For quad support I believe this bounds check can be builtin.