Skip to content
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

[Feature] Gradients for Backgrounds #1597

Closed

Conversation

bungoboingo
Copy link
Contributor

@bungoboingo bungoboingo commented Dec 13, 2022

Gradients are now usable as a Background variant

When creating a background with a gradient, the syntax is slightly different than when creating it on a Canvas.

Example of building a gradient for background:

container::Appearance {
    background: Gradient::linear(Radians(PI/3.0)) //or Degrees(45.0)!
        .add_stop(0.0, Color::from_rgb8(255, 0, 0))
        .add_stop(0.5, Color::from_rgb8(0, 255, 0))
        .add_stop(1.0, Color::from_rgb8(0, 0, 255))
        .build()
        .into(),
    ..Default::default()
}

Users can declare a Gradient with a specified Angle (rads or degrees), and add up to =8 ColorStops along that angle. The bounds of the gradient will be calculated from the bounds of the quad that it is filling.

Changes to Canvas gradient syntax

Users can no longer specify a Position::Absolute or a Position::Relative; now users can only specify an absolute start & end position when using a gradient as a Fill on a Canvas. This change was made to simplify the gradient API. Calculating bounds is possible with a mesh but would increase the cost of our tessellation phase which is not ideal.

New syntax for creating a Gradient fill on a Canvas (very similar to old one):

let gradient = Gradient::linear(
    Point::ORIGIN,
    Point::new(
        bounds.x + bounds.size().width,
        bounds.y + bounds.size().height,
    ),
)
.add_stop(0.0, Color::from_rgb8(255, 0, 0))
.add_stop(0.5, Color::from_rgb8(0, 255, 0))
.add_stop(1.0, Color::from_rgb8(0, 0, 255))
.build();
    
frame.fill_rectangle(Point::ORIGIN, bounds.size(), gradient);

Some API notes

Due to this differing requirement for both Canvas and Background gradient types, I've had to redeclare Gradients separately in core & graphics. I messed about with keeping one builder for both, but it led to too many unexpected behaviors. Duping the Gradient declaration between the two now has no unintended consequences of, for example, declaring a Gradient with an angle as a fill for a mesh, which is undefined behavior. Let me know what you think!

Changes to Gradient rendering pipeline

Gradients are now stored as a vertex type, GradientVertex2D which takes a position & flattened gradient data. This change allows us to stay fast & reduce draw calls in quad instancing/triangle drawing. This will also make gradients more accessible for different platforms (eg for WASM target), as it removes the requirements of storage buffer support.

Old gradients bench (rendering 5151 static gradients):
Screen Shot 2022-12-12 at 6 21 23 PM

New gradients bench (same 5151 static gradients)!:
Screen Shot 2022-12-12 at 6 22 48 PM

GPU is now much more happy!

This does have the tradeoff of forcing a lower maximum number of color stops, which is now 8 compared to.. like 186,000. If anyone has any issues with this please let me know in the comments below!

Addition of several new benches crates

I've added four new static benchmarks to examples/benches. Not sure this is the best place for them, I could see them perhaps being added to the profiling crate in my profiling PR, or to a separate repo entirely. Let me know what you think!
I've moved these to https://github.com/bungoboingo/iced_benches for the time being until we can figure out how we want to integrate the benches into our CI.

Support added

WASM should now be able to compile gradient shaders & use gradients as I've removed the need of storage buffers. Let me know if you see any issues!

Testing

Tested:
M1 mac (WGPU + metal, tiny-skia)
Linux (WGPU + Vulkan, tiny-skia)
Windows 10 (WGPU + DirectX, tiny-skia)

🌈 🌈 🌈
Welcoming all feedback on the API & other changes! 🎉

@bungoboingo bungoboingo changed the title [WIP] [Feature] Gradients for Backgrounds [Feature] Gradients for Backgrounds Dec 20, 2022
@bungoboingo bungoboingo marked this pull request as ready for review December 20, 2022 06:25
Cargo.toml Outdated Show resolved Hide resolved
core/Cargo.toml Outdated Show resolved Hide resolved
glow/src/quad/core.rs Outdated Show resolved Hide resolved
@bungoboingo bungoboingo force-pushed the feat/background-gradients branch 2 times, most recently from fba463d to d662a2d Compare December 20, 2022 17:00
core/src/gradient.rs Outdated Show resolved Hide resolved
Copy link
Member

@hecrj hecrj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking awesome!

No specific showstoppers for me 🎉 Just a bunch of suggestions here and there. Let me know what you think!

core/src/angle.rs Outdated Show resolved Hide resolved
core/src/gradient.rs Outdated Show resolved Hide resolved
core/src/gradient.rs Outdated Show resolved Hide resolved
core/Cargo.toml Outdated Show resolved Hide resolved
examples/tour/src/main.rs Show resolved Hide resolved
core/src/gradient.rs Show resolved Hide resolved
glow/src/quad/core.rs Outdated Show resolved Hide resolved
glow/src/shader/quad/core/gradient.frag Outdated Show resolved Hide resolved
wgpu/src/quad.rs Outdated Show resolved Hide resolved
wgpu/src/shader/triangle/solid.wgsl Outdated Show resolved Hide resolved
@bungoboingo
Copy link
Contributor Author

bungoboingo commented Jan 11, 2023

Added ooooonnnneeee last commit d33e3e6 to add dithering to the gradient shaders to smooth out banding

@@ -38,6 +42,8 @@ vec4 gradient(
//if a gradient has a start/end stop that is identical, the mesh will have a transparent fill
vec4 color;

float noise_granularity = 0.3/255.0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seemed like a good amount to me, but I'm also pretty blind IRL so if it still looks band-y or too grainy, let me know.

@hecrj hecrj modified the milestones: 0.7.0, 0.8.0 Jan 14, 2023
@greatest-ape
Copy link
Contributor

I would love to see this get merged, as it also seems to fix #1625!

@bungoboingo bungoboingo changed the base branch from master to advanced-text March 22, 2023 20:54
@bungoboingo bungoboingo force-pushed the feat/background-gradients branch 2 times, most recently from a756bf0 to dc82fb0 Compare March 23, 2023 00:32
@bungoboingo
Copy link
Contributor Author

bungoboingo commented Mar 23, 2023

Re-targeted this to advanced-text! Notable changes:

  • Got rid of unnecessary buffer abstractions, modified the existing wgpu::Buffer to include offsets.
  • Nuked all the GL code obv
  • Shuffled the shader-specific data packing out of the main Gradient declarations
  • Added gradient backgrounds for tiny-skia as well

@bungoboingo
Copy link
Contributor Author

bungoboingo commented Mar 23, 2023

Updated gradient builder to not use a Result in 8b6be3d. I think this is a cleaner API overall despite taking a hit in explicitness. Invalid ColorStops will now be logged at a warn level, but other than that the Gradient will be built in whatever way it can be.

If stops are added after the 8th, they will be silently ignored.
If no stops are added, with wgpu it will just render nothing, which I think makes sense! With tiny-skia since it requires at least one stop, I decided to just have it render as a solid black color if no stops were added to the gradient.

@hecrj hecrj modified the milestones: 0.9.0, 0.10.0 Apr 12, 2023
@hecrj hecrj deleted the branch iced-rs:advanced-text May 11, 2023 14:45
@hecrj hecrj closed this May 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request rendering styling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants