@@ -4,6 +4,7 @@ use super::{
44 command:: CommandBuffer ,
55 instance:: Instance ,
66 surface:: Surface ,
7+ texture,
78} ;
89
910#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
@@ -197,6 +198,24 @@ pub struct Gpu {
197198}
198199
199200impl Gpu {
201+ /// Whether the provided surface format supports the sample count for render attachments.
202+ pub fn supports_sample_count_for_surface (
203+ & self ,
204+ format : super :: surface:: SurfaceFormat ,
205+ sample_count : u32 ,
206+ ) -> bool {
207+ return self . supports_sample_count ( format. to_wgpu ( ) , sample_count) ;
208+ }
209+
210+ /// Whether the provided depth format supports the sample count for render attachments.
211+ pub fn supports_sample_count_for_depth (
212+ & self ,
213+ format : texture:: DepthFormat ,
214+ sample_count : u32 ,
215+ ) -> bool {
216+ return self . supports_sample_count ( format. to_wgpu ( ) , sample_count) ;
217+ }
218+
200219 /// Borrow the adapter used to create the device.
201220 ///
202221 /// Crate-visible to avoid exposing raw `wgpu` to higher layers.
@@ -245,11 +264,50 @@ impl Gpu {
245264 let iter = list. into_iter ( ) . map ( |cb| cb. into_raw ( ) ) ;
246265 self . queue . submit ( iter) ;
247266 }
267+
268+ fn supports_sample_count (
269+ & self ,
270+ format : wgpu:: TextureFormat ,
271+ sample_count : u32 ,
272+ ) -> bool {
273+ if sample_count <= 1 {
274+ return true ;
275+ }
276+
277+ let features = self . adapter . get_texture_format_features ( format) ;
278+ if !features
279+ . allowed_usages
280+ . contains ( wgpu:: TextureUsages :: RENDER_ATTACHMENT )
281+ {
282+ return false ;
283+ }
284+
285+ match sample_count {
286+ 2 => features
287+ . flags
288+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X2 ) ,
289+ 4 => features
290+ . flags
291+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X4 ) ,
292+ 8 => features
293+ . flags
294+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X8 ) ,
295+ 16 => features
296+ . flags
297+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X16 ) ,
298+ _ => false ,
299+ }
300+ }
248301}
249302
250303#[ cfg( test) ]
251304mod tests {
252305 use super :: * ;
306+ use crate :: wgpu:: {
307+ instance,
308+ surface,
309+ texture,
310+ } ;
253311
254312 #[ test]
255313 fn gpu_build_error_wraps_request_device_error ( ) {
@@ -260,4 +318,121 @@ mod tests {
260318 fn assert_from_impl < T : From < wgpu:: RequestDeviceError > > ( ) { }
261319 assert_from_impl :: < GpuBuildError > ( ) ;
262320 }
321+
322+ /// Create an offscreen GPU for sample-count support tests.
323+ ///
324+ /// Returns `None` when no compatible adapter is available so tests can be
325+ /// skipped instead of failing.
326+ fn create_test_gpu ( ) -> Option < Gpu > {
327+ let instance = instance:: InstanceBuilder :: new ( )
328+ . with_label ( "gpu-test-instance" )
329+ . build ( ) ;
330+ return GpuBuilder :: new ( )
331+ . with_label ( "gpu-test-device" )
332+ . build ( & instance, None )
333+ . ok ( ) ;
334+ }
335+
336+ /// Accepts zero or single-sample attachments for any format.
337+ #[ test]
338+ fn single_sample_always_supported ( ) {
339+ let gpu = match create_test_gpu ( ) {
340+ Some ( gpu) => gpu,
341+ None => {
342+ eprintln ! (
343+ "Skipping single_sample_always_supported: no compatible GPU adapter"
344+ ) ;
345+ return ;
346+ }
347+ } ;
348+ let surface_format =
349+ surface:: SurfaceFormat :: from_wgpu ( wgpu:: TextureFormat :: Bgra8UnormSrgb ) ;
350+ let depth_format = texture:: DepthFormat :: Depth32Float ;
351+
352+ assert ! ( gpu. supports_sample_count_for_surface( surface_format, 1 ) ) ;
353+ assert ! ( gpu. supports_sample_count_for_surface( surface_format, 0 ) ) ;
354+ assert ! ( gpu. supports_sample_count_for_depth( depth_format, 1 ) ) ;
355+ assert ! ( gpu. supports_sample_count_for_depth( depth_format, 0 ) ) ;
356+ }
357+
358+ /// Rejects sample counts that are outside the supported set.
359+ #[ test]
360+ fn unsupported_sample_count_rejected ( ) {
361+ let gpu = match create_test_gpu ( ) {
362+ Some ( gpu) => gpu,
363+ None => {
364+ eprintln ! (
365+ "Skipping unsupported_sample_count_rejected: no compatible GPU adapter"
366+ ) ;
367+ return ;
368+ }
369+ } ;
370+ let surface_format =
371+ surface:: SurfaceFormat :: from_wgpu ( wgpu:: TextureFormat :: Bgra8Unorm ) ;
372+ let depth_format = texture:: DepthFormat :: Depth32Float ;
373+
374+ assert ! ( !gpu. supports_sample_count_for_surface( surface_format, 3 ) ) ;
375+ assert ! ( !gpu. supports_sample_count_for_depth( depth_format, 3 ) ) ;
376+ }
377+
378+ /// Mirrors the adapter's texture feature flags for surface formats.
379+ #[ test]
380+ fn surface_support_matches_texture_features ( ) {
381+ let gpu = match create_test_gpu ( ) {
382+ Some ( gpu) => gpu,
383+ None => {
384+ eprintln ! (
385+ "Skipping surface_support_matches_texture_features: \
386+ no compatible GPU adapter"
387+ ) ;
388+ return ;
389+ }
390+ } ;
391+ let surface_format =
392+ surface:: SurfaceFormat :: from_wgpu ( wgpu:: TextureFormat :: Bgra8UnormSrgb ) ;
393+ let features = gpu
394+ . adapter
395+ . get_texture_format_features ( surface_format. to_wgpu ( ) ) ;
396+ let expected = features
397+ . allowed_usages
398+ . contains ( wgpu:: TextureUsages :: RENDER_ATTACHMENT )
399+ && features
400+ . flags
401+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X4 ) ;
402+
403+ assert_eq ! (
404+ gpu. supports_sample_count_for_surface( surface_format, 4 ) ,
405+ expected
406+ ) ;
407+ }
408+
409+ /// Mirrors the adapter's texture feature flags for depth formats.
410+ #[ test]
411+ fn depth_support_matches_texture_features ( ) {
412+ let gpu = match create_test_gpu ( ) {
413+ Some ( gpu) => gpu,
414+ None => {
415+ eprintln ! (
416+ "Skipping depth_support_matches_texture_features: \
417+ no compatible GPU adapter"
418+ ) ;
419+ return ;
420+ }
421+ } ;
422+ let depth_format = texture:: DepthFormat :: Depth32Float ;
423+ let features = gpu
424+ . adapter
425+ . get_texture_format_features ( depth_format. to_wgpu ( ) ) ;
426+ let expected = features
427+ . allowed_usages
428+ . contains ( wgpu:: TextureUsages :: RENDER_ATTACHMENT )
429+ && features
430+ . flags
431+ . contains ( wgpu:: TextureFormatFeatureFlags :: MULTISAMPLE_X4 ) ;
432+
433+ assert_eq ! (
434+ gpu. supports_sample_count_for_depth( depth_format, 4 ) ,
435+ expected
436+ ) ;
437+ }
263438}
0 commit comments