Skip to content

Commit 8cbd2f3

Browse files
committed
[add] anisotropy clamp to the sampler builder.
1 parent 43c91a7 commit 8cbd2f3

File tree

1 file changed

+108
-4
lines changed

1 file changed

+108
-4
lines changed

crates/lambda-rs-platform/src/wgpu/texture.rs

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ pub struct SamplerBuilder {
528528
address_w: AddressMode,
529529
lod_min: f32,
530530
lod_max: f32,
531+
anisotropy_clamp: u16,
531532
}
532533

533534
impl Default for SamplerBuilder {
@@ -549,6 +550,7 @@ impl SamplerBuilder {
549550
address_w: AddressMode::ClampToEdge,
550551
lod_min: 0.0,
551552
lod_max: 32.0,
553+
anisotropy_clamp: 1,
552554
};
553555
}
554556

@@ -621,7 +623,65 @@ impl SamplerBuilder {
621623
return self;
622624
}
623625

624-
fn to_descriptor(&self) -> wgpu::SamplerDescriptor<'_> {
626+
/// Set the maximum anisotropic filtering level.
627+
///
628+
/// Valid values are `1` (disabled) through `16`. Values outside this range
629+
/// are clamped. Higher values improve texture quality at oblique viewing
630+
/// angles but increase GPU cost.
631+
///
632+
/// Common values:
633+
/// - `1`: Disabled (default)
634+
/// - `4`: Good balance of quality and performance
635+
/// - `8`: High quality
636+
/// - `16`: Maximum quality
637+
///
638+
/// Note: Anisotropic filtering is most effective with linear filtering and
639+
/// mipmapped textures. wgpu also requires all filter modes to be linear when
640+
/// anisotropy is enabled; otherwise anisotropy is disabled.
641+
///
642+
/// ```no_run
643+
/// # use lambda_platform::wgpu::texture::{FilterMode, SamplerBuilder};
644+
/// # fn demo(gpu: &lambda_platform::wgpu::gpu::Gpu) {
645+
/// // High-quality sampler for floor/wall textures viewed at angles
646+
/// let aniso_sampler = SamplerBuilder::new()
647+
/// .linear_clamp()
648+
/// .with_mip_filter(FilterMode::Linear)
649+
/// .with_anisotropy_clamp(8)
650+
/// .build(gpu);
651+
///
652+
/// // Default sampler (no anisotropy) for UI textures
653+
/// let ui_sampler = SamplerBuilder::new().linear_clamp().build(gpu);
654+
/// # let _ = (aniso_sampler, ui_sampler);
655+
/// # }
656+
/// ```
657+
pub fn with_anisotropy_clamp(mut self, clamp: u16) -> Self {
658+
self.anisotropy_clamp = clamp.clamp(1, 16);
659+
return self;
660+
}
661+
662+
fn to_descriptor(
663+
&self,
664+
max_supported_anisotropy: u16,
665+
) -> wgpu::SamplerDescriptor<'_> {
666+
let max_supported_anisotropy = max_supported_anisotropy.clamp(1, 16);
667+
let mut anisotropy_clamp = self
668+
.anisotropy_clamp
669+
.clamp(1, 16)
670+
.min(max_supported_anisotropy);
671+
if anisotropy_clamp > 1
672+
&& !matches!(
673+
(self.min_filter, self.mag_filter, self.mipmap_filter),
674+
(FilterMode::Linear, FilterMode::Linear, FilterMode::Linear)
675+
)
676+
{
677+
logging::warn!(
678+
"Sampler anisotropy requested ({}), but all filters must be \
679+
linear; anisotropy disabled.",
680+
anisotropy_clamp
681+
);
682+
anisotropy_clamp = 1;
683+
}
684+
625685
return wgpu::SamplerDescriptor {
626686
label: self.label.as_deref(),
627687
address_mode_u: self.address_u.to_wgpu(),
@@ -632,13 +692,23 @@ impl SamplerBuilder {
632692
mipmap_filter: self.mipmap_filter.to_wgpu_mipmap(),
633693
lod_min_clamp: self.lod_min,
634694
lod_max_clamp: self.lod_max,
695+
anisotropy_clamp,
635696
..Default::default()
636697
};
637698
}
638699

639700
/// Create the sampler on the provided device.
640701
pub fn build(self, gpu: &Gpu) -> Sampler {
641-
let desc = self.to_descriptor();
702+
let downlevel = gpu.adapter().get_downlevel_capabilities();
703+
let max_supported_anisotropy = if downlevel
704+
.flags
705+
.contains(wgpu::DownlevelFlags::ANISOTROPIC_FILTERING)
706+
{
707+
16
708+
} else {
709+
1
710+
};
711+
let desc = self.to_descriptor(max_supported_anisotropy);
642712
let raw = gpu.device().create_sampler(&desc);
643713
return Sampler {
644714
raw,
@@ -1051,7 +1121,7 @@ mod tests {
10511121
#[test]
10521122
fn sampler_builder_defaults_map() {
10531123
let b = SamplerBuilder::new();
1054-
let d = b.to_descriptor();
1124+
let d = b.to_descriptor(16);
10551125
assert_eq!(d.address_mode_u, wgpu::AddressMode::ClampToEdge);
10561126
assert_eq!(d.address_mode_v, wgpu::AddressMode::ClampToEdge);
10571127
assert_eq!(d.address_mode_w, wgpu::AddressMode::ClampToEdge);
@@ -1060,19 +1130,53 @@ mod tests {
10601130
assert_eq!(d.mipmap_filter, wgpu::MipmapFilterMode::Nearest);
10611131
assert_eq!(d.lod_min_clamp, 0.0);
10621132
assert_eq!(d.lod_max_clamp, 32.0);
1133+
assert_eq!(d.anisotropy_clamp, 1);
10631134
}
10641135

10651136
#[test]
10661137
fn sampler_builder_linear_clamp_map() {
10671138
let b = SamplerBuilder::new()
10681139
.linear_clamp()
10691140
.with_mip_filter(FilterMode::Linear);
1070-
let d = b.to_descriptor();
1141+
let d = b.to_descriptor(16);
10711142
assert_eq!(d.address_mode_u, wgpu::AddressMode::ClampToEdge);
10721143
assert_eq!(d.address_mode_v, wgpu::AddressMode::ClampToEdge);
10731144
assert_eq!(d.address_mode_w, wgpu::AddressMode::ClampToEdge);
10741145
assert_eq!(d.mag_filter, wgpu::FilterMode::Linear);
10751146
assert_eq!(d.min_filter, wgpu::FilterMode::Linear);
10761147
assert_eq!(d.mipmap_filter, wgpu::MipmapFilterMode::Linear);
10771148
}
1149+
1150+
#[test]
1151+
fn sampler_builder_anisotropy_is_clamped_and_passed_through() {
1152+
let b = SamplerBuilder::new()
1153+
.linear_clamp()
1154+
.with_mip_filter(FilterMode::Linear)
1155+
.with_anisotropy_clamp(8);
1156+
assert_eq!(b.to_descriptor(16).anisotropy_clamp, 8);
1157+
assert_eq!(b.to_descriptor(4).anisotropy_clamp, 4);
1158+
assert_eq!(b.to_descriptor(1).anisotropy_clamp, 1);
1159+
}
1160+
1161+
#[test]
1162+
fn sampler_builder_anisotropy_clamps_to_valid_range() {
1163+
assert_eq!(
1164+
SamplerBuilder::new()
1165+
.linear_clamp()
1166+
.with_mip_filter(FilterMode::Linear)
1167+
.with_anisotropy_clamp(0)
1168+
.to_descriptor(16)
1169+
.anisotropy_clamp,
1170+
1
1171+
);
1172+
assert_eq!(
1173+
SamplerBuilder::new()
1174+
.linear_clamp()
1175+
.with_mip_filter(FilterMode::Linear)
1176+
.with_anisotropy_clamp(100)
1177+
.to_descriptor(16)
1178+
.anisotropy_clamp,
1179+
16
1180+
);
1181+
}
10781182
}

0 commit comments

Comments
 (0)