-
Notifications
You must be signed in to change notification settings - Fork 142
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
Support setting AA method dynamically #400
Conversation
66bdcb1
to
951cacc
Compare
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.
Mostly some style considerations
src/lib.rs
Outdated
|
||
/// The anti-aliasing specialization that should be used when creating the pipelines. `None` | ||
/// initializes all variants. | ||
pub preferred_antialiasing_method: Option<AaConfig>, |
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.
Would a bitflags be better here?
I guess I'd need to consider what the use cases are for the different modes? Why would you choose one over another. Should it be user configurable?
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.
A partial answer to this is that we think we'll probably want to end up rendering glyphs with area AA and general paths with MSAA. But that speaks to a setting that's even more dynamic than per-render.
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.
Would a bitflags be better here?
A bitfield is probably a good idea. I changed this to use a struct-of-bools instead of bitflags for now.
I mainly wanted to provide a way for existing clients to avoid compiling the variants they don't need. Currently each AaConfig
enum maps to exactly one fine
stage permutation but this may evolve over time with more configs, such as a single pipeline that is capable of multiple AA modes. Even in that world it may be desirable to turn off AA logic in that pipeline if the client doesn't need it.
I guess I'd need to consider what the use cases are for the different modes? Why would you choose one over another. Should it be user configurable?
This is a great question. Each AA method has a certain trade-off: analytic area AA provides very high quality anti-aliasing but results in conflation artifacts with certain paths (#49) (see also the labyrinth
and conflation_artifacts
scenes). As @raphlinus said, this is likely the preferred way to render text where quality really matters and glyphs are unlikely to be crafted in a way that can result in conflation artifacts.
The MSAA methods OTOH do not suffer from conflation artifacts but the AA quality is noticeably poorer compared to analytic area. This may be a reasonable trade-off for an application that doesn't have control over all content (for example an SVG viewer or the Canvas API implementation in web a browser). In fact, Skia has had to disable area AA algorithms in the past following user complaints (see crbug.com/913223 and skbug.com/40038110) if you're interested in some of the history of this in Chromium).
Between MSAAx16 and MSAAx8 the trade-off is between performance and quality but maybe that gap will narrow as we invest more time into optimizations.
For now, I chose to provide the option but we can always revisit this.
src/lib.rs
Outdated
/// TODO: Consider evolving this so that the CPU stages can be configured dynamically via | ||
/// `RenderParams`. |
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.
Should this be a doc comment rather than just a comment?
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.
Done. To clarify, you wanted this to be a regular comment instead of a doc comment, correct?
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.
Looks good. I agree with most of Daniel's comments, and just had some golfing to make the logic hopefully a little simpler - it feels just a bit clunky and I'm slightly worried about what will happen as the number of permutations grows. But this is definitely useful to have!
Of course, we might reduce permutations by having multiple aa methods present in the same shader, but one nice thing about this setup is that we can experiment with the effect of shared memory size (with effect on occupancy but also likely a nontrivial effect from just clearing the memory, especially as this isn't always optimized well).
src/lib.rs
Outdated
|
||
/// The anti-aliasing specialization that should be used when creating the pipelines. `None` | ||
/// initializes all variants. | ||
pub preferred_antialiasing_method: Option<AaConfig>, |
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.
A partial answer to this is that we think we'll probably want to end up rendering glyphs with area AA and general paths with MSAA. But that speaks to a setting that's even more dynamic than per-render.
src/render.rs
Outdated
AaConfig::Msaa16 => crate::mask::make_mask_lut_16(), | ||
AaConfig::Msaa8 => crate::mask::make_mask_lut(), | ||
_ => unreachable!(), | ||
}; | ||
let buf = recording.upload("mask lut", mask_lut); | ||
self.mask_buf = Some(buf.into()); | ||
} | ||
let shader = match fine.aa_config { |
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.
Personally I'd call this fine_shader
.
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.
Done.
src/shaders.rs
Outdated
for (i, aa_mode) in AA_MODES.iter().enumerate() { | ||
if options | ||
.preferred_antialiasing_method | ||
.as_ref() |
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.
Could the as_ref
be eliminated by comparing m != *aa_mode
? It's Copy
for this reason.
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.
Done.
951cacc
to
2962959
Compare
I agree that this is a little clunky and it would be good to figure out a better way to specify the desired pipeline permutations. For now, this is scoped to 3 AA settings and I imagine it wouldn't be too hard to extend this to an additional "dynamic" mode if we were to explore that. |
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.
Not approving as I haven't had a chance to run this yet, but the code looks good.
There are a couple of small style points, one of which isn't necessarily an improvement (especially if it makes rustfmt break up the aa_modes across 20 lines, which it might accidentally do)
examples/with_winit/src/lib.rs
Outdated
@@ -356,6 +374,7 @@ fn run( | |||
.unwrap_or(Color::BLACK), | |||
width, | |||
height, | |||
antialiasing_method: aa_config, |
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.
I'd probably inline this (so that the comment above about base_colour logic is in the right place)
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.
aa_config
gets reused below so I wanted to have a single binding for it. I moved things around so that the comment is positioned better.
src/shaders.rs
Outdated
} | ||
let (range_end_offset, label, aa_config) = match *msaa_info { | ||
Some((label, config)) => (0, label, Some(config)), | ||
None => (1, "fine_area", None), |
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.
(I had a big comment written out here, which GitHub mobile helpfully deleted)
But broadly, I was wondering if all of this should be inlined into aa_mode, i.e. make it a (bool, usize, &str, Option<&str>)
.
If we were doing that, I'd then replace the usize offset with the pipeline resources, so fine_area would be:
(support.area, &fine_resources[..7], "fine_area", None)
(Where 7 might not be the right number, but trying to check it lead to the deletion of the previous version of this comment)
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.
Done. I just folded the offset into the tuple to keep the column width manageable.
This replaces the static anti-aliasing setting with a dynamic option in the form of two new settings (one used during pipeline creation and one used during a render): - The `FullShaders` collection now maintains up to 3 `fine` stage pipeline variants. This can be driven using a new optional `RendererOptions` field called `preferred_antialiasing_method`, which determines which fine stage pipeline variants should get instantiated at start up. - `RenderParams` now requires an `AaConfig` which selects which `fine` stage variant to use. - Added a new key binding (`M`) to the `with_winit` example to dynamically cycle through all 3 AA methods.
Instead of passing in a single optional mode to enable, the caller can now specify which set of AA methods to compile.
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.
This needs some merge conflict fixing, but hopefully that should be easy. I haven't run this version but have run a previous version, so I'm ok as long as things didn't get broken. And if they did, that can be a followup PR :)
@@ -180,7 +182,11 @@ fn run( | |||
stats.clear_min_and_max(); | |||
} | |||
Some(VirtualKeyCode::M) => { | |||
aa_config_ix = (aa_config_ix + 1) % AA_CONFIGS.len(); | |||
aa_config_ix = if modifiers.shift() { |
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.
Personally I would keep the mod n behavior (as the reverse is less discoverable), but that's a style preference. Note though that we do have +/- and mod n for cycling through the test scenes.
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.
That's fair, the scene cycling logic is actually structured this way (though bound to arrow keys instead of using a modifier) so I just followed that here for consistency.
c8dcbb5
to
1efb3a5
Compare
This replaces the static anti-aliasing setting with a dynamic option in the form of two new settings (one used during pipeline creation and one used during a render):
The
FullShaders
collection now maintains up to 3fine
stage pipeline variants. This can be driven using a new optionalRendererOptions
field calledpreferred_antialiasing_method
, which determines which fine stage pipeline variants should get instantiated at start up.RenderParams
now requires anAaConfig
which selects whichfine
stage variant to use.Added a new key binding (
M
) to thewith_winit
example to dynamically cycle through all 3 AA methods.