@@ -1021,6 +1021,84 @@ impl super::Device {
1021
1021
pub fn shared_instance ( & self ) -> & super :: InstanceShared {
1022
1022
& self . shared . instance
1023
1023
}
1024
+
1025
+ fn check_for_oom ( & self , needs_host_access : bool , size : u64 ) -> Result < ( ) , crate :: DeviceError > {
1026
+ if self
1027
+ . shared
1028
+ . enabled_extensions
1029
+ . contains ( & ext:: memory_budget:: NAME )
1030
+ {
1031
+ let get_physical_device_properties = self
1032
+ . shared
1033
+ . instance
1034
+ . get_physical_device_properties
1035
+ . as_ref ( )
1036
+ . unwrap ( ) ;
1037
+
1038
+ let mut memory_budget_properties =
1039
+ vk:: PhysicalDeviceMemoryBudgetPropertiesEXT :: default ( ) ;
1040
+
1041
+ let mut memory_properties = vk:: PhysicalDeviceMemoryProperties2 :: default ( )
1042
+ . push_next ( & mut memory_budget_properties) ;
1043
+
1044
+ unsafe {
1045
+ get_physical_device_properties. get_physical_device_memory_properties2 (
1046
+ self . shared . physical_device ,
1047
+ & mut memory_properties,
1048
+ ) ;
1049
+ }
1050
+
1051
+ let mut host_visible_heaps = [ false ; vk:: MAX_MEMORY_HEAPS ] ;
1052
+ let mut device_local_heaps = [ false ; vk:: MAX_MEMORY_HEAPS ] ;
1053
+
1054
+ let memory_properties = memory_properties. memory_properties ;
1055
+
1056
+ for i in 0 ..memory_properties. memory_type_count {
1057
+ let memory_type = memory_properties. memory_types [ i as usize ] ;
1058
+ let flags = memory_type. property_flags ;
1059
+
1060
+ if flags. intersects (
1061
+ vk:: MemoryPropertyFlags :: LAZILY_ALLOCATED | vk:: MemoryPropertyFlags :: PROTECTED ,
1062
+ ) {
1063
+ continue ; // not used by gpu-alloc
1064
+ }
1065
+
1066
+ if flags. contains ( vk:: MemoryPropertyFlags :: HOST_VISIBLE ) {
1067
+ host_visible_heaps[ memory_type. heap_index as usize ] = true ;
1068
+ }
1069
+
1070
+ if flags. contains ( vk:: MemoryPropertyFlags :: DEVICE_LOCAL ) {
1071
+ device_local_heaps[ memory_type. heap_index as usize ] = true ;
1072
+ }
1073
+ }
1074
+
1075
+ let heaps = if needs_host_access {
1076
+ host_visible_heaps
1077
+ } else {
1078
+ device_local_heaps
1079
+ } ;
1080
+
1081
+ // NOTE: We might end up checking multiple heaps since gpu-alloc doesn't have a way
1082
+ // for us to query the heap the resource will end up on. But this is unlikely,
1083
+ // there is usually only one heap on integrated GPUs and two on dedicated GPUs.
1084
+
1085
+ for ( i, check) in heaps. iter ( ) . enumerate ( ) {
1086
+ if !check {
1087
+ continue ;
1088
+ }
1089
+
1090
+ let heap_usage = memory_budget_properties. heap_usage [ i] ;
1091
+ let heap_budget = memory_budget_properties. heap_budget [ i] ;
1092
+
1093
+ // Make sure we don't exceed 90% of the budget
1094
+ if heap_usage + size >= heap_budget / 100 * 90 {
1095
+ return Err ( crate :: DeviceError :: OutOfMemory ) ;
1096
+ }
1097
+ }
1098
+ }
1099
+
1100
+ Ok ( ( ) )
1101
+ }
1024
1102
}
1025
1103
1026
1104
impl crate :: Device for super :: Device {
@@ -1066,6 +1144,10 @@ impl crate::Device for super::Device {
1066
1144
desc. memory_flags . contains ( crate :: MemoryFlags :: TRANSIENT ) ,
1067
1145
) ;
1068
1146
1147
+ let needs_host_access = alloc_usage. contains ( gpu_alloc:: UsageFlags :: HOST_ACCESS ) ;
1148
+
1149
+ self . check_for_oom ( needs_host_access, req. size ) ?;
1150
+
1069
1151
let alignment_mask = req. alignment - 1 ;
1070
1152
1071
1153
let block = unsafe {
@@ -1176,6 +1258,8 @@ impl crate::Device for super::Device {
1176
1258
) -> Result < super :: Texture , crate :: DeviceError > {
1177
1259
let image = self . create_image_without_memory ( desc, None ) ?;
1178
1260
1261
+ self . check_for_oom ( false , image. requirements . size ) ?;
1262
+
1179
1263
let block = unsafe {
1180
1264
self . mem_allocator . lock ( ) . alloc (
1181
1265
& * self . shared ,
@@ -2435,6 +2519,10 @@ impl crate::Device for super::Device {
2435
2519
& self ,
2436
2520
desc : & wgt:: QuerySetDescriptor < crate :: Label > ,
2437
2521
) -> Result < super :: QuerySet , crate :: DeviceError > {
2522
+ // Assume each query is 256 bytes.
2523
+ // On an AMD W6800 with driver version 32.0.12030.9, occlusion queries are 256.
2524
+ self . check_for_oom ( true , desc. count as u64 * 256 ) ?;
2525
+
2438
2526
let ( vk_type, pipeline_statistics) = match desc. ty {
2439
2527
wgt:: QueryType :: Occlusion => (
2440
2528
vk:: QueryType :: OCCLUSION ,
@@ -2764,6 +2852,8 @@ impl crate::Device for super::Device {
2764
2852
. map_err ( super :: map_host_device_oom_and_ioca_err) ?;
2765
2853
let req = self . shared . raw . get_buffer_memory_requirements ( raw_buffer) ;
2766
2854
2855
+ self . check_for_oom ( false , req. size ) ?;
2856
+
2767
2857
let block = self . mem_allocator . lock ( ) . alloc (
2768
2858
& * self . shared ,
2769
2859
gpu_alloc:: Request {
@@ -2808,7 +2898,7 @@ impl crate::Device for super::Device {
2808
2898
. shared
2809
2899
. raw
2810
2900
. create_query_pool ( & vk_info, None )
2811
- . map_err ( super :: map_host_oom_and_ioca_err ) ?;
2901
+ . map_err ( super :: map_host_device_oom_err ) ?;
2812
2902
Some ( raw)
2813
2903
} else {
2814
2904
None
0 commit comments