mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
make memory pressure detection optional and configurable
This commit is contained in:
parent
5bd3a25cf7
commit
3b72d59a3c
@ -148,6 +148,10 @@ impl GPU {
|
||||
&wgpu_types::InstanceDescriptor {
|
||||
backends,
|
||||
flags: wgpu_types::InstanceFlags::from_build_config(),
|
||||
memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds {
|
||||
for_resource_creation: Some(97),
|
||||
for_device_loss: Some(99),
|
||||
},
|
||||
backend_options: wgpu_types::BackendOptions {
|
||||
dx12: wgpu_types::Dx12BackendOptions {
|
||||
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
|
||||
|
||||
@ -43,6 +43,10 @@ pub fn initialize_instance(backends: wgpu::Backends, params: &TestParameters) ->
|
||||
Instance::new(&wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
flags,
|
||||
memory_budget_thresholds: wgpu::MemoryBudgetThresholds {
|
||||
for_resource_creation: Some(99),
|
||||
for_device_loss: None,
|
||||
},
|
||||
backend_options: wgpu::BackendOptions {
|
||||
dx12: wgpu::Dx12BackendOptions {
|
||||
shader_compiler: dx12_shader_compiler,
|
||||
|
||||
@ -39,6 +39,7 @@ mod request_adapter_error {
|
||||
wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
flags: wgpu::InstanceFlags::default(),
|
||||
memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),
|
||||
backend_options: wgpu::BackendOptions::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +123,7 @@ impl Instance {
|
||||
let hal_desc = hal::InstanceDescriptor {
|
||||
name: "wgpu",
|
||||
flags: self.flags,
|
||||
memory_budget_thresholds: instance_desc.memory_budget_thresholds,
|
||||
backend_options: instance_desc.backend_options.clone(),
|
||||
};
|
||||
|
||||
|
||||
@ -94,6 +94,7 @@ impl<A: hal::Api> Example<A> {
|
||||
let instance_desc = hal::InstanceDescriptor {
|
||||
name: "example",
|
||||
flags: wgpu_types::InstanceFlags::from_build_config().with_env(),
|
||||
memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds::default(),
|
||||
// Can't rely on having DXC available, so use FXC instead
|
||||
backend_options: wgpu_types::BackendOptions::default(),
|
||||
};
|
||||
|
||||
@ -238,6 +238,7 @@ impl<A: hal::Api> Example<A> {
|
||||
let instance_desc = hal::InstanceDescriptor {
|
||||
name: "example",
|
||||
flags: wgpu_types::InstanceFlags::default(),
|
||||
memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds::default(),
|
||||
backend_options: wgpu_types::BackendOptions {
|
||||
dx12: Dx12BackendOptions {
|
||||
shader_compiler: wgpu_types::Dx12Compiler::default_dynamic_dxc(),
|
||||
|
||||
@ -54,6 +54,7 @@ impl super::Adapter {
|
||||
adapter: DxgiAdapter,
|
||||
library: &Arc<D3D12Lib>,
|
||||
instance_flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||
// Create the device so that we can get the capabilities.
|
||||
@ -515,6 +516,7 @@ impl super::Adapter {
|
||||
private_caps,
|
||||
presentation_timer,
|
||||
workarounds,
|
||||
memory_budget_thresholds,
|
||||
dxc_container,
|
||||
},
|
||||
info,
|
||||
@ -653,6 +655,7 @@ impl crate::Adapter for super::Adapter {
|
||||
memory_hints,
|
||||
self.private_caps,
|
||||
&self.library,
|
||||
self.memory_budget_thresholds,
|
||||
self.dxc_container.clone(),
|
||||
)?;
|
||||
Ok(crate::OpenDevice {
|
||||
|
||||
@ -47,6 +47,7 @@ impl super::Device {
|
||||
memory_hints: &wgt::MemoryHints,
|
||||
private_caps: super::PrivateCapabilities,
|
||||
library: &Arc<D3D12Lib>,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||
) -> Result<Self, crate::DeviceError> {
|
||||
if private_caps
|
||||
@ -159,6 +160,7 @@ impl super::Device {
|
||||
private_caps,
|
||||
device_memblock_size,
|
||||
host_memblock_size,
|
||||
memory_budget_thresholds,
|
||||
};
|
||||
|
||||
let mut rtv_pool =
|
||||
@ -1937,17 +1939,18 @@ impl crate::Device for super::Device {
|
||||
),
|
||||
};
|
||||
|
||||
let info = self
|
||||
.shared
|
||||
.adapter
|
||||
.query_video_memory_info(Dxgi::DXGI_MEMORY_SEGMENT_GROUP_LOCAL)?;
|
||||
if let Some(threshold) = self.shared.memory_budget_thresholds.for_resource_creation {
|
||||
let info = self
|
||||
.shared
|
||||
.adapter
|
||||
.query_video_memory_info(Dxgi::DXGI_MEMORY_SEGMENT_GROUP_LOCAL)?;
|
||||
|
||||
// Assume each query is 256 bytes.
|
||||
// On an AMD W6800 with driver version 32.0.12030.9, occlusion and pipeline statistics are 256, timestamp is 8.
|
||||
// Assume each query is 256 bytes.
|
||||
// On an AMD W6800 with driver version 32.0.12030.9, occlusion and pipeline statistics are 256, timestamp is 8.
|
||||
|
||||
// Make sure we don't exceed 90% of the budget
|
||||
if info.CurrentUsage + desc.count as u64 * 256 >= info.Budget / 10 * 9 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
if info.CurrentUsage + desc.count as u64 * 256 >= info.Budget / 100 * threshold as u64 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
}
|
||||
|
||||
let mut raw = None::<Direct3D12::ID3D12QueryHeap>;
|
||||
@ -2326,13 +2329,16 @@ impl crate::Device for super::Device {
|
||||
}
|
||||
|
||||
fn check_if_oom(&self) -> Result<(), crate::DeviceError> {
|
||||
let Some(threshold) = self.shared.memory_budget_thresholds.for_device_loss else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let info = self
|
||||
.shared
|
||||
.adapter
|
||||
.query_video_memory_info(Dxgi::DXGI_MEMORY_SEGMENT_GROUP_LOCAL)?;
|
||||
|
||||
// Make sure we don't exceed 95% of the budget
|
||||
if info.CurrentUsage >= info.Budget / 100 * 95 {
|
||||
if info.CurrentUsage >= info.Budget / 100 * threshold as u64 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
|
||||
@ -2345,8 +2351,7 @@ impl crate::Device for super::Device {
|
||||
.adapter
|
||||
.query_video_memory_info(Dxgi::DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)?;
|
||||
|
||||
// Make sure we don't exceed 95% of the budget
|
||||
if info.CurrentUsage >= info.Budget / 100 * 95 {
|
||||
if info.CurrentUsage >= info.Budget / 100 * threshold as u64 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +109,7 @@ impl crate::Instance for super::Instance {
|
||||
_lib_dxgi: lib_dxgi,
|
||||
supports_allow_tearing,
|
||||
flags: desc.flags,
|
||||
memory_budget_thresholds: desc.memory_budget_thresholds,
|
||||
dxc_container,
|
||||
})
|
||||
}
|
||||
@ -142,7 +143,13 @@ impl crate::Instance for super::Instance {
|
||||
adapters
|
||||
.into_iter()
|
||||
.filter_map(|raw| {
|
||||
super::Adapter::expose(raw, &self.library, self.flags, self.dxc_container.clone())
|
||||
super::Adapter::expose(
|
||||
raw,
|
||||
&self.library,
|
||||
self.flags,
|
||||
self.memory_budget_thresholds,
|
||||
self.dxc_container.clone(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -460,6 +460,7 @@ pub struct Instance {
|
||||
supports_allow_tearing: bool,
|
||||
_lib_dxgi: DxgiLib,
|
||||
flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||
}
|
||||
|
||||
@ -591,6 +592,7 @@ pub struct Adapter {
|
||||
// Note: this isn't used right now, but we'll need it later.
|
||||
#[allow(unused)]
|
||||
workarounds: Workarounds,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||
}
|
||||
|
||||
@ -635,6 +637,7 @@ struct DeviceShared {
|
||||
private_caps: PrivateCapabilities,
|
||||
device_memblock_size: u64,
|
||||
host_memblock_size: u64,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
}
|
||||
|
||||
unsafe impl Send for DeviceShared {}
|
||||
|
||||
@ -526,6 +526,10 @@ impl<'a> DeviceAllocationContext<'a> {
|
||||
.GetResourceAllocationInfo(0, std::slice::from_ref(desc))
|
||||
};
|
||||
|
||||
let Some(threshold) = self.shared.memory_budget_thresholds.for_resource_creation else {
|
||||
return Ok(allocation_info);
|
||||
};
|
||||
|
||||
let memory_segment_group = match location {
|
||||
MemoryLocation::Unknown => unreachable!(),
|
||||
MemoryLocation::GpuOnly => Dxgi::DXGI_MEMORY_SEGMENT_GROUP_LOCAL,
|
||||
@ -552,9 +556,8 @@ impl<'a> DeviceAllocationContext<'a> {
|
||||
MemoryLocation::CpuToGpu | MemoryLocation::GpuToCpu => self.shared.host_memblock_size,
|
||||
};
|
||||
|
||||
// Make sure we don't exceed 90% of the budget
|
||||
if info.CurrentUsage + allocation_info.SizeInBytes.max(memblock_size)
|
||||
>= info.Budget / 10 * 9
|
||||
>= info.Budget / 100 * threshold as u64
|
||||
{
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
|
||||
@ -1741,6 +1741,7 @@ bitflags!(
|
||||
pub struct InstanceDescriptor<'a> {
|
||||
pub name: &'a str,
|
||||
pub flags: wgt::InstanceFlags,
|
||||
pub memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
pub backend_options: wgt::BackendOptions,
|
||||
}
|
||||
|
||||
|
||||
@ -95,6 +95,7 @@ impl crate::Instance for Context {
|
||||
},
|
||||
name: _,
|
||||
flags: _,
|
||||
memory_budget_thresholds: _,
|
||||
} = *desc;
|
||||
if enable {
|
||||
Ok(Context)
|
||||
|
||||
@ -1027,6 +1027,15 @@ impl super::Device {
|
||||
needs_host_access: bool,
|
||||
size: u64,
|
||||
) -> Result<(), crate::DeviceError> {
|
||||
let Some(threshold) = self
|
||||
.shared
|
||||
.instance
|
||||
.memory_budget_thresholds
|
||||
.for_resource_creation
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if !self
|
||||
.shared
|
||||
.enabled_extensions
|
||||
@ -1096,8 +1105,7 @@ impl super::Device {
|
||||
let heap_usage = memory_budget_properties.heap_usage[i];
|
||||
let heap_budget = memory_budget_properties.heap_budget[i];
|
||||
|
||||
// Make sure we don't exceed 90% of the budget
|
||||
if heap_usage + size >= heap_budget / 100 * 90 {
|
||||
if heap_usage + size >= heap_budget / 100 * threshold as u64 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
}
|
||||
@ -3008,6 +3016,15 @@ impl crate::Device for super::Device {
|
||||
}
|
||||
|
||||
fn check_if_oom(&self) -> Result<(), crate::DeviceError> {
|
||||
let Some(threshold) = self
|
||||
.shared
|
||||
.instance
|
||||
.memory_budget_thresholds
|
||||
.for_device_loss
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if !self
|
||||
.shared
|
||||
.enabled_extensions
|
||||
@ -3041,8 +3058,7 @@ impl crate::Device for super::Device {
|
||||
let heap_usage = memory_budget_properties.heap_usage[i as usize];
|
||||
let heap_budget = memory_budget_properties.heap_budget[i as usize];
|
||||
|
||||
// Make sure we don't exceed 95% of the budget
|
||||
if heap_usage >= heap_budget / 100 * 95 {
|
||||
if heap_usage >= heap_budget / 100 * threshold as u64 {
|
||||
return Err(crate::DeviceError::OutOfMemory);
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,6 +347,7 @@ impl super::Instance {
|
||||
debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
|
||||
extensions: Vec<&'static CStr>,
|
||||
flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
has_nv_optimus: bool,
|
||||
drop_callback: Option<crate::DropCallback>,
|
||||
) -> Result<Self, crate::InstanceError> {
|
||||
@ -397,6 +398,7 @@ impl super::Instance {
|
||||
extensions,
|
||||
drop_guard,
|
||||
flags,
|
||||
memory_budget_thresholds,
|
||||
debug_utils,
|
||||
get_physical_device_properties,
|
||||
entry,
|
||||
@ -860,6 +862,7 @@ impl crate::Instance for super::Instance {
|
||||
debug_utils,
|
||||
extensions,
|
||||
desc.flags,
|
||||
desc.memory_budget_thresholds,
|
||||
has_nv_optimus,
|
||||
None,
|
||||
)
|
||||
|
||||
@ -162,6 +162,7 @@ pub struct InstanceShared {
|
||||
extensions: Vec<&'static CStr>,
|
||||
drop_guard: Option<crate::DropGuard>,
|
||||
flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
debug_utils: Option<DebugUtils>,
|
||||
get_physical_device_properties: Option<khr::get_physical_device_properties2::Instance>,
|
||||
entry: ash::Entry,
|
||||
|
||||
@ -14,6 +14,8 @@ pub struct InstanceDescriptor {
|
||||
pub backends: Backends,
|
||||
/// Flags to tune the behavior of the instance.
|
||||
pub flags: InstanceFlags,
|
||||
/// Memory budget thresholds used by some backends.
|
||||
pub memory_budget_thresholds: MemoryBudgetThresholds,
|
||||
/// Options the control the behavior of various backends.
|
||||
pub backend_options: BackendOptions,
|
||||
}
|
||||
@ -23,6 +25,7 @@ impl Default for InstanceDescriptor {
|
||||
Self {
|
||||
backends: Backends::all(),
|
||||
flags: InstanceFlags::default(),
|
||||
memory_budget_thresholds: MemoryBudgetThresholds::default(),
|
||||
backend_options: BackendOptions::default(),
|
||||
}
|
||||
}
|
||||
@ -48,6 +51,7 @@ impl InstanceDescriptor {
|
||||
Self {
|
||||
backends,
|
||||
flags,
|
||||
memory_budget_thresholds: MemoryBudgetThresholds::default(),
|
||||
backend_options,
|
||||
}
|
||||
}
|
||||
@ -225,6 +229,24 @@ impl InstanceFlags {
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory budget thresholds used by backends to try to avoid high memory pressure situations.
|
||||
///
|
||||
/// Currently only the D3D12 and (optionally) Vulkan backends support these options.
|
||||
#[derive(Default, Clone, Debug, Copy)]
|
||||
pub struct MemoryBudgetThresholds {
|
||||
/// Threshold at which texture, buffer, query set and acceleration structure creation will start to return OOM errors.
|
||||
/// This is a percent of the memory budget reported by native APIs.
|
||||
///
|
||||
/// If not specified, resource creation might still return OOM errors.
|
||||
pub for_resource_creation: Option<u8>,
|
||||
|
||||
/// Threshold at which devices will become lost due to memory pressure.
|
||||
/// This is a percent of the memory budget reported by native APIs.
|
||||
///
|
||||
/// If not specified, devices might still become lost due to memory pressure.
|
||||
pub for_device_loss: Option<u8>,
|
||||
}
|
||||
|
||||
/// Options that are passed to a given backend.
|
||||
///
|
||||
/// Part of [`InstanceDescriptor`].
|
||||
|
||||
@ -77,17 +77,17 @@ pub use wgt::{
|
||||
Dx12BackendOptions, Dx12Compiler, DxcShaderModel, DynamicOffset, Extent3d, Face, Features,
|
||||
FeaturesWGPU, FeaturesWebGPU, FilterMode, FrontFace, GlBackendOptions, GlFenceBehavior,
|
||||
Gles3MinorVersion, HalCounters, ImageSubresourceRange, IndexFormat, InstanceDescriptor,
|
||||
InstanceFlags, InternalCounters, Limits, MemoryHints, MultisampleState, NoopBackendOptions,
|
||||
Origin2d, Origin3d, PipelineStatisticsTypes, PollError, PollStatus, PolygonMode,
|
||||
PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState,
|
||||
PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, RequestAdapterError,
|
||||
SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderRuntimeChecks,
|
||||
ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess,
|
||||
SurfaceCapabilities, SurfaceStatus, TexelCopyBufferLayout, TextureAspect, TextureDimension,
|
||||
TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType,
|
||||
TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace, VertexAttribute,
|
||||
VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT,
|
||||
COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT,
|
||||
InstanceFlags, InternalCounters, Limits, MemoryBudgetThresholds, MemoryHints, MultisampleState,
|
||||
NoopBackendOptions, Origin2d, Origin3d, PipelineStatisticsTypes, PollError, PollStatus,
|
||||
PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp,
|
||||
PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil,
|
||||
RequestAdapterError, SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel,
|
||||
ShaderRuntimeChecks, ShaderStages, StencilFaceState, StencilOperation, StencilState,
|
||||
StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TexelCopyBufferLayout, TextureAspect,
|
||||
TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures,
|
||||
TextureSampleType, TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace,
|
||||
VertexAttribute, VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync,
|
||||
COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT,
|
||||
QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT,
|
||||
};
|
||||
#[expect(deprecated)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user